【问题标题】:Cross Compiling For Arch Arm Does Not Produce A Functional ExecutableArch Arm 的交叉编译不会产生功能可执行文件
【发布时间】:2018-10-06 08:19:51
【问题描述】:

我将Arch Arm 安装到 Rpi3 上,然后 rsync'd sysroot 到安装在 Lenovo thinkpad 上的 x86_64 Arch Linux。

然后我安装了arm-linux-gnueabihf Linaro 交叉编译器

为避免出现任何问题,我在编译中使用了绝对路径:

/home/sameh/Rpi/Compiler/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc\
 --sysroot=/home/sameh/Rpi/Arch/ArmV7/root\
 -o stress stress.c -lm

代码编译得很好,但是当我在 Rpi3 上执行它时它没有输出。

它不会冻结 Pi,我可以 ps aux 并查看 fork() 创建的子进程。

但没有打印任何调试语句,也没有任何进程退出。

编辑

此代码基于stress 库。对于 MCVE,我将其最小化为仅 hogcpu 函数

#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>

int hogcpu (void);

int
hogcpu (void)
{
  for(int i=0; i < 1000000; i++)
    sqrt (rand ());
  return 0;
}

int main()
{

  struct timespec start, end;
  double cpu_time_used;
  int pid, children = 0, retval = 0;
  long forks;
  int do_dryrun = 0;
  long long do_backoff = 3000;

  long long do_cpu = 1;
  long long backoff, timeout = 0;

  /* Calculate the backoff value so we get good fork throughput.  */
  backoff = do_backoff * forks;

  clock_gettime(CLOCK_REALTIME, &start); 

  while ((forks = (do_cpu + do_io + do_vm + do_hdd)))
  {
    if (do_cpu)
    {
      switch (pid = fork ())
        {
        case 0:            /* child */
          alarm (timeout);
          usleep (backoff);
          exit (hogcpu ());
        case -1:           /* error */
          break;
        default:
          ++children;
        }
      --do_cpu;
    }

  }
  /* Wait for our children to exit.  */
  while (children)
  {
    int status, ret;

    if ((pid = wait (&status)) > 0)
    {
      --children;
      if (WIFEXITED (status))
      {
        if ((ret = WEXITSTATUS (status)) == 0)
        {
          printf( "<-- worker %i returned normally\n", pid);
        }
        else
        {
          printf( "<-- worker %i returned error %i\n", pid, ret);
          ++retval;
          printf( "now reaping child worker processes\n");
          if (signal (SIGUSR1, SIG_IGN) == SIG_ERR)
            printf( "handler error: %s\n", strerror (errno));
          if (kill (-1 * getpid (), SIGUSR1) == -1)
            printf( "kill error: %s\n", strerror (errno));
        }
      }
    }
  }

  clock_gettime(CLOCK_REALTIME, &end); 
  cpu_time_used = (end.tv_nsec = start.tv_nsec) / 1000000000.0;
  /* Print final status message.  */
  if (retval)
  {
    printf( "failed run completed in %.2f s\n", cpu_time_used);
  }
  else
  {
    printf( "successful run completed in -- %.2f s\n", cpu_time_used);
  }

  exit (retval);
}

我可以在 Pi 上成功编译并执行它:

[alarm@control ~]$ gcc stress.c -o stress -lm
[alarm@control ~]$ ./stress 
<-- worker 16834 returned normally
<-- worker 16835 returned normally
<-- worker 16836 returned normally
successful run completed in -- 0.90 s

但是,当交叉编译并传输到 Pi 时,上述行为就是我所看到的。

注意

这很可能与clock_gettime 通话有关。当我将其替换为 clock() 函数调用时,我可以在笔记本电脑上编译并运行它,但在 Pi 上使用 gcc 编译具有与上述相同的行为。

当使用clock_gettime 并在 Pi 上编译时,它工作正常。

【问题讨论】:

  • 你能把它归结为 MCVE 吗?
  • 好的,现在试试

标签: c cross-compiling raspberry-pi3 archlinux archlinux-arm


【解决方案1】:

这里的问题是long forks; 变量是如何初始化的。我对编译器不是很精通,但是因为forks没有初始化,所以backoff = do_backoff * forks;的计算结果是随机的负数。

这阻止了调用 usleep (backoff); 完成。所以将forks 初始化为 1 解决了这个问题。

我原以为forks 应该被编译器初始化为0,就像bss_data 的过去一样,所以我不知道为什么它没有。可能需要对这部分进行更多研究,但是代码现在可以通过交叉编译很好地执行。

【讨论】:

  • "我原以为 forks 应该在 bss_data 的过去被编译器初始化为 0,所以我不知道为什么它没有" forks 是本地的变量,如果你让它未初始化,它将得到堆栈/寄存器中发生的任何内容;更抽象地说,C 标准说从未初始化的变量中读取是未定义的行为。 .bss 用于全局变量(更准确地说:用于静态存储持续时间变量,即全局变量 + static 局部变量,它们是伪装的全局变量),如果未显式初始化,则保证为 0。
  • 顺便说一句,在使用-Wall -Wextra -O3 编译时会立即发现这一点。您应该养成在编译时始终启用大多数警告以避免这些陷阱的习惯。
  • 不错!感谢您的提示!
  • godbolt.org/g/8SpbWH 例如。顺便说一句,您的原始代码 do_iodo_vmdo_hdd 丢失了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-13
  • 1970-01-01
  • 1970-01-01
  • 2016-05-26
  • 2013-01-19
  • 2021-02-17
相关资源
最近更新 更多