在交叉编译的armhf中调用main()之前的SEGFAULT [英] segfault before main() is called in cross-compiled armhf

查看:34
本文介绍了在交叉编译的armhf中调用main()之前的SEGFAULT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我终于在Ubuntu Xenial x86_64主机上交叉编译并链接了一个二进制文件,以便在Raspberry Pi 4的ARMHF上运行。

我的工具链来自ARM,放在$TOOLCHAIN中。

我的sysroot是放置在$RASPBIAN_ROOT中的循环装载的Raspberry OS映像。

这是一个示例编译行:

$TOOLCHAIN/gcc-arm-8.3-2019.03/bin/arm-linux-gnueabihf-g++ -std=c++11 --sysroot=$RASPBIAN_ROOT 
  -D_ARM_ -DOTHER_DEFINES 
  -v -w -fexceptions -fpermissive -pipe 
  -mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard 
  -Wabi-tag -D_GLIBCXX_USE_CXX11_ABI=0 
  -fno-use-cxa-atexit 
  -g 
  -I . -I .. -I extlib1/include -I extlib2/include -I $RASPBIAN_ROOT/usr/include/libxml2 
  -I $TOOLCHAIN/gcc-arm-8.3-2019.03/arm-none-linux-gnueabihf/libc/usr/include 
  -I $RASPBIAN_ROOT/usr/include/arm-linux-gnueabihf 
  -I $RASPBIAN_ROOT/usr/include 
  -c File.cpp -o obj/linux/armhf/debug/File.o
也有一些.c文件。下面是链接行:

$TOOLCHAIN/gcc-arm-8.3-2019.03/bin/arm-linux-gnueabihf-ld.gold 
-L ../localdependency 
-L $RASPBIAN_ROOT/opt/vc/lib 
-L $RASPBIAN_ROOT/usr/lib/arm-linux-gnueabihf 
-L $RASPBIAN_ROOT/lib 
-L$RASPBIAN_ROOT/usr/lib 
-L $RASPBIAN_ROOT/usr/lib/gcc/arm-linux-gnueabihf/8 -o bin/linux/armhf/debug/executable obj/linux/armhf/debug/File.o ... 
$RASPBIAN_ROOT/usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o 
$RASPBIAN_ROOT/usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o 
$RASPBIAN_ROOT/usr/lib/gcc/arm-linux-gnueabihf/8/libgcc_eh.a 
--verbose --sysroot=$RASPBIAN_ROOT 
-lbcm_host -lvcos -lvchiq_arm -lcurl -lxml2 
-lpthread -lz -lm -ldl -lstdc++ -lc -lgcc -lgcc_s

.这似乎会产生一个可执行文件。(为了可读性,对两行都进行了编辑。)

但是,当在pi上运行时,我得到了一个段故障:

$ ./executable param1 param2
Segmentation fault

如果我尝试调试,它甚至达不到main()

$ gdb executable
GNU gdb (Raspbian 8.2.1-2) 8.2.1

...

(gdb) b main
Breakpoint 1 at 0x2c7c74: file main.cpp, line 7029.
(gdb) r param1 param2
Starting program: /home/user/executable param1 param2
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.

Program received signal SIGSEGV, Segmentation fault.
0xb6f97420 in __libc_enable_asynccancel () at ../nptl/cancellation.c:33
33  ../nptl/cancellation.c: No such file or directory.
(gdb) bt
#0  0xb6f97420 in __libc_enable_asynccancel () at ../nptl/cancellation.c:33
#1  0xb6f77968 in __GI___libc_write (nbytes=407, buf=0xb6fdc838 <banner>, fd=1) at ../sysdeps/unix/sysv/linux/write.c:26
#2  __GI___libc_write (fd=fd@entry=1, buf=0xb6fdc838 <banner>, nbytes=nbytes@entry=407) at ../sysdeps/unix/sysv/linux/write.c:24
#3  0xb6ec98d8 in __libc_print_version () at version.c:71
#4  __libc_main () at version.c:71
#5  0x00000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) 

当我看到";警告:找不到动态链接器断点函数。";(并且正在尝试找出ld.so来自包中的哪个位置)时,我更倾向于相信我的工具链/sysroot/libs配置不正确。

一个简单的HelloWorld交叉编译并正常执行:

#include <iostream>

int main(int argc, char* argv[]) {
    int i = 1;
    std::cout << "hello world " << i << std::endl;
    return 0;
}
$ ./rpihello 
hello world 1

$ ldd rpihello 
    linux-vdso.so.1 (0xbef33000)
    /usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so => /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so (0xb6f90000)
    libstdc++.so.6 => /usr/lib/arm-linux-gnueabihf/libstdc++.so.6 (0xb6e30000)
    libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6dae000)
    libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6d81000)
    libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6c33000)
    /lib/ld-linux-armhf.so.3 (0xb6fa5000)

编辑%1

因为nptl/cancellation.c似乎来自libc,所以我仔细检查了一下我有所有必需的包,我相信我有(否则我的PI会有很多问题):

pi$ cat /etc/ld.so.conf.d/*
/opt/vc/lib
# Multiarch support
/usr/local/lib/arm-linux-gnueabihf
/lib/arm-linux-gnueabihf
/usr/lib/arm-linux-gnueabihf
/usr/lib/arm-linux-gnueabihf/libfakeroot
# libc default configuration
/usr/local/lib

pi$ apt list --installed | grep ^libc
libc-ares2/now 1.14.0-1 armhf [installed,upgradable to: 1.14.0-1+deb10u1]
libc-bin/stable,now 2.28-10+rpi1 armhf [installed]
libc-dev-bin/stable,now 2.28-10+rpi1 armhf [installed,automatic]
libc-l10n/stable,now 2.28-10+rpi1 all [installed,automatic]
libc6-dbg/stable,now 2.28-10+rpi1 armhf [installed]
libc6-dev/stable,now 2.28-10+rpi1 armhf [installed]
libc6-pic/stable,now 2.28-10+rpi1 armhf [installed]
libc6/stable,now 2.28-10+rpi1 armhf [installed]
libcc1-0/stable,now 8.3.0-6+rpi1 armhf [installed,automatic]

pi$ apt list --installed | grep ^libgcc
libgcc-6-dev/stable,now 6.5.0-1+rpi1+b1 armhf [installed,automatic]
libgcc-8-dev/stable,now 8.3.0-6+rpi1 armhf [installed,automatic]
libgcc1-dbg/stable,now 1:8.3.0-6+rpi1 armhf [installed,automatic]
libgcc1/stable,now 1:8.3.0-6+rpi1 armhf [installed]

所以我仍然认为我以某种方式借用了交叉编译/链接。


编辑%2

我已经设法在raspberry pi上编译了我的代码库,生成的二进制代码显示了与交叉编译的结果相同的结果。因此,要么是我编译错误,要么是我的sysroot和pi的系统都有点问题。


编辑%3

rpi $ readelf -dW myexecutable

Dynamic section at offset 0x664e58 contains 48 entries:
  Tag        Type                         Name/Value
 0x00000003 (PLTGOT)                     0x6716d4
 0x00000002 (PLTRELSZ)                   5856 (bytes)
 0x00000017 (JMPREL)                     0x2d940
 0x00000014 (PLTREL)                     REL
 0x00000011 (REL)                        0x2d2e0
 0x00000012 (RELSZ)                      1632 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000006 (SYMTAB)                     0x8148
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000005 (STRTAB)                     0xfb48
 0x0000000a (STRSZ)                      94185 (bytes)
 0x6ffffef5 (GNU_HASH)                   0x26b34
 0x00000004 (HASH)                       0x2930c
 0x00000001 (NEEDED)                     Shared library: [libbcm_host.so]
 0x00000001 (NEEDED)                     Shared library: [libvcos.so]
 0x00000001 (NEEDED)                     Shared library: [libvchiq_arm.so]
 0x00000001 (NEEDED)                     Shared library: [libjson.so]
 0x00000001 (NEEDED)                     Shared library: [libmylocallib.so]
...
 0x00000001 (NEEDED)                     Shared library: [libpthread.so.0]
 0x00000001 (NEEDED)                     Shared library: [libz.so.1]
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libdl.so.2]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so.6]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x00000019 (INIT_ARRAY)                 0x66dd60
 0x0000001b (INIT_ARRAYSZ)               244 (bytes)
 0x0000001a (FINI_ARRAY)                 0x66de54
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x6ffffff0 (VERSYM)                     0x2c1b0
 0x6ffffffe (VERNEED)                    0x2d0f0
 0x6fffffff (VERNEEDNUM)                 9
 0x00000000 (NULL)                       0x0

我觉得这很有趣:

rpi $ file myexecutable
myexecutable: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /usr/lib/libc.so.1, with debug_info, not stripped
rpi $ file `which ls`
/bin/ls: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=67a394390830ea3ab4e83b5811c66fea9784ee69, stripped

我的可执行文件不应该使用%ld作为解释器吗?


编辑%4

Iadded[2]--dynamic-linker=/lib/ld-linux-armhf.so.3到我的链接器行,但现在没有堆栈:

Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb) bt
#0  0x00000000 in ?? ()
(gdb) 

运行strace executable最后几行如下:

rt_sigprocmask(SIG_BLOCK, NULL, ~[ILL TRAP BUS FPE KILL SEGV STOP RTMIN RT_1], 8) = 0
rt_sigaction(SIGILL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0xb5e55120}, NULL, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
clock_gettime(CLOCK_MONOTONIC_COARSE, {tv_sec=6336, tv_nsec=768744979}) = 0
gettimeofday({tv_sec=1631533208, tv_usec=497816}, NULL) = 0
openat(AT_FDCWD, "/dev/urandom", O_RDONLY) = 3
read(3, "3144bJn3616240f203216I257306251r202v232263210374222276TN33,[3A233", 32) = 32
close(3)                                = 0
openat(AT_FDCWD, "/dev/urandom", O_RDONLY) = 3
read(3, "301231203~G6Ey_262Y24134216F2448w2365Z213376223260322zwo334+e", 32) = 32
close(3)                                = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV +++
Segmentation fault

/dev/urandom确实存在。


编辑5

$ readelf -h executable
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          40514564 (bytes into file)
  Flags:                             0x5000400, Version5 EABI, hard-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         8
  Size of section headers:           40 (bytes)
  Number of section headers:         37
  Section header string table index: 36

我认为入口点地址不应为0x0。


编辑%6

我已经在PI3和ARM-QEMU chroot上编译了代码-结果相同。

raspbercrypi.org

我找到的解决方案是与来自推荐答案的toolchain交叉编译,并将--sysroot=设置为Raspbian映像。他们的releases或多或少效仿了Debian,始终支持所有现有的树莓派。
CXXLD都指向他们的g++,也就是说确定链接标志的是GCC。如果需要,我可以使用-Wl,..
-Wabi-tag -D_GLIBCXX_USE_CXX11_ABI=0外,CFLAGS是相当标准的。


Raspbian将其下载URL格式从Buster<[3-6](2020-02-13)改为10.4(2020-05-28),并开始提供完整版和精简版。我用的是后者。
因为这些镜像通常几乎没有可用的空间,所以我首先extend镜像文件、分区(P2)和底层文件系统,这样我就可以通过quemu-arm转换到sysroot来安装满足项目依赖性的-dev包。

这篇关于在交叉编译的armhf中调用main()之前的SEGFAULT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆