wiki主页:https://sourceware.org/glibc/wiki/Debugging/Development_Debugging
1. 调试加载器
有几种调试加载器的场景:
- 应用程序崩溃过早
应用程序执行main前的libc初始化代码中有一个错误,这时必须调试加载器才能调查初始化代码。 - 加载器本身崩溃
这可能是由于加载器中的一个运行时错误,需要直接调试加载器。 - 加载器在其符号解析器代码中出现故障
这时可以从应用程序主过程进入加载器进行调试。 - 正在使用备用加载器并且需要调试应用程序或库
使用备用加载器的应用程序或库必须通过调试加载器并进入应用程序或库来调试。
1.1. 在应用主程序之前调试加载器
直接 GDB 调试加载器,然后直接在调试中的加载器加载应用程序。如:
bash-4.2$ gdb /home/carlos/build/glibc/elf/ld.so
GNU gdb (GDB) Fedora 7.6.1-42.fc19
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/carlos/build/glibc/elf/ld.so...done.
(gdb) set exec-wrapper env LD_LIBRARY_PATH=/home/carlos/build/glibc:/home/carlos/build/glibc/elf:/home/carlos/build/glibc/math
(gdb) break _start
Breakpoint 1 at 0x11e0
(gdb) run /home/carlos/test
Starting program: /home/carlos/build/glibc/elf/ld.so /home/carlos/test
Breakpoint 1, 0x00005555555551e0 in _start ()
(gdb)
需要注意的一件重要事情是,不能使用set env来设置环境变量,否则影响动态加载器。这个原因是因为 gdb 默认在子 shell 中运行下级(inferior),这样做有几个原因,最重要的是参数扩展。如果为动态加载器设置了环境变量,它们也会影响子 shell,并可能导致子 shell 无法启动下级。
1.2. 单步执行加载器
加载器的某些部分可以被单步执行(比如运行时解析器)。这些部分更容易调试,因为您可以简单地从您的应用程序进入它们。如:
bash-4.2$ gdb /home/carlos/test
GNU gdb (GDB) Fedora 7.6.1-42.fc19
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/carlos/test...done.
(gdb) break main
Breakpoint 1 at 0x400534: file test.c, line 8.
(gdb) r
Starting program: /home/carlos/test
Breakpoint 1, main () at test.c:8
8 keys[512] = 42;
(gdb) n
9 printf ("%d\n", keys[512]);
(gdb) si
0x0000000000400544 9 printf ("%d\n", keys[512]);
(gdb)
0x0000000000400546 9 printf ("%d\n", keys[512]);
(gdb)
0x000000000040054b 9 printf ("%d\n", keys[512]);
(gdb)
0x0000000000400550 9 printf ("%d\n", keys[512]);
(gdb)
0x0000000000400410 in printf@plt ()
(gdb)
0x0000000000400416 in printf@plt ()
(gdb)
0x000000000040041b in printf@plt ()
(gdb)
0x0000000000400400 in ?? ()
(gdb)
0x0000000000400406 in ?? ()
(gdb)
_dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:34
34 subq $56,%rsp
(gdb)
在示例中,可以看到 x86_64 上的调试器单步执行过程链接表(3 条指令),然后是另外 3 条指令(始终跳转到解析器中的 PLT 条目,并且所有惰性 PLT 条目在启动时都绑定到该条目)跳转到运行时解析器例程。glibc 中此例程的目的是定位您需要的符号,将 PLT 条目绑定到该符号,并使用您的参数调用该符号。这仅在您有惰性符号解析时发生,如果启用了 LD_BIND_NOW,您将看到从 PLT 直接跳转到 printf。
1.3. 使用备用加载器进行调试
通常,在开发过程中,GLIBC 将安装到独立环境中。为了在此环境中测试应用程序,应用程序将使用安装在独立环境中的加载器启动,而不是系统加载器。这创建了一个独特的调试环境,为了调试应用程序或库的准确的执行环境,用户必须启动加载器的调试,然后进入应用程序或库。
这给 GNU 调试器gdb在查找有关应用程序和库的符号信息方面带来了一些挑战。当 GDB 调试加载器时,它只是为加载器单独加载符号信息。您需要执行一些特殊操作来支持 GDB 找到应用程序和库的符号和地址。
按照标题为“使用备用加载程序调试”部分下的加载器调试页面中描述的技术进行操作。
2. 将错误构建中的代码注入到良好构建中的测试用例中
很多时候,人们会处理一些代码(例如 memcpy),这些代码将被 GLIBC 的基本组件(如加载器)拾取和使用。如果这段代码有问题,那么第一次使用加载器时,它可能会使加载器崩溃(即segmentation violation段违规),这将阻止 make check 运行任何测试。
2.1. 设想前提条件
我们将调查发生这种情况的设想,并介绍一些调试分段违规的方法。
- 为架构开发了一个新版本的 memcpy,它可能有一些问题。
- 在 /home/user/glibc/good-build/ 中有一个干净的不带memcpy 补丁的构建
- 在 /home/user/glibc/bad-build/ 中有一个带有 memcpy 补丁的构建
- GLIBC 为修改过的特定代码段提供了一个测试用例,例如 test-memcpy。
- 这个测试用例永远不会运行,因为加载器在 test-memcpy 运行之前在另一个测试中崩溃,这可能是由于 memcpy 中的错误导致的。
2.2. 设想调试选项
以下调试选项提供了几种调试此问题的技术。我们将对第三个选项最感兴趣。
- 尝试调试加载器:此时调试加载器可能为时过早,因为您甚至不知道为 memcpy 插入的代码是否会通过 memcpy 测试用例。如果您知道此时有必要调试加载器,请参阅上面关于“调试加载器”的部分。
- 将独立测试用例静态链接到有问题的 .o 文件。这种方法可以检测到一些错误,但它不能告诉您为什么加载器可能会轰炸(bombing)代码。
- 将成功构建的 GLIBC 测试用例静态链接到有问题的 .o 文件。这是更好的方法,但更复杂。
2.3. 识别故障点
这些示例中的 GLIBC 构建是使用cross-compiling=yes构建的,因此在构建过程中不会运行加载器。
在这种情况下,只要没有语法错误,GLIBC make阶段就会成功完成。通常,在首次使用新构建的 GLIBC 之前,不会出现基本的运行时错误。
要执行的 GLIBC 的第一个片段是在 GLIBC 的make check 中运行的加载器。
如果cross-compiling=no(这是默认值),那么加载器将在构建期间运行,可能会在 make 阶段遇到构建失败。
保存make和make check阶段输出以供以后搜素的好形式,例如:
> make -j4 2>&1 | tee _make64_1
> make check 2>&1 | tee _check64_1
查找失败的地方是从_check64_1输出开始。
/bin/sh: line 1: 10667 Segmentation fault GCONV_PATH=/home/user/glibc/bad-build/glibc64/iconvdata LC_ALL=C MALLOC_TRACE=/home/user/glibc/bad-build/glibc64/nptl/tst-stack3.mtrace /home/user/glibc/bad-build/glibc64/elf/ld64.so.1 --library-path /home/user/glibc/bad-build/glibc64:/home/user/glibc/bad-build/glibc64/math:/home/user/glibc/bad-build/glibc64/elf:/home/user/glibc/bad-build/glibc64/dlfcn:/home/user/glibc/bad-build/glibc64/nss:/home/user/glibc/bad-build/glibc64/nis:/home/user/glibc/bad-build/glibc64/rt:/home/user/glibc/bad-build/glibc64/resolv:/home/user/glibc/bad-build/glibc64/crypt:/home/user/glibc/bad-build/glibc64/nptl /home/user/glibc/bad-build/glibc64/nptl/tst-stack3 >/home/user/glibc/bad-build/glibc64/nptl/tst-stack3.out
make[2]: *** [/home/user/glibc/bad-build/glibc64/nptl/tst-stack3.out] Error 139
加载器中发生段错误的可能性很大。让我们检查:
> /home/user/glibc/bad-build/glibc64/elf/ld64.so.1
Segmentation fault
由于我们的 memcpy 版本有问题,加载器中肯定存在问题。我们将使用调试选项三中的技术来进行调试。
2.4. 从错误的构建中提取有问题的 .o 文件
搜索错误构建的make输出_make64_1并确定 memcpy.o 的生成位置。
/opt/toolchain/bin/gcc -m64 …/sysdeps/powerpc/powerpc64/cell/memcpy.S -c -I…/include -I/home/user/glibc/bad-build/glibc64/string -I/home/user/glibc/bad-build/glibc64 -I…/sysdeps/powerpc/powerpc64/elf -I…/sysdeps/powerpc/elf -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/cell/fpu -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/cell -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/fpu -I…/sysdeps/powerpc/powerpc64/fpu -I…/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64 -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64 -I…/sysdeps/unix/sysv/linux/wordsize-64 -I…/nptl/sysdeps/unix/sysv/linux/powerpc -I…/sysdeps/unix/sysv/linux/powerpc -I…/sysdeps/ieee754/ldbl-128ibm -I…/sysdeps/ieee754/ldbl-opt -I…/nptl/sysdeps/unix/sysv/linux -I…/nptl/sysdeps/pthread -I…/sysdeps/pthread -I…/sysdeps/unix/sysv/linux -I…/sysdeps/gnu -I…/sysdeps/unix/common -I…/sysdeps/unix/mman -I…/sysdeps/unix/inet -I…/nptl/sysdeps/unix/sysv -I…/sysdeps/unix/sysv -I…/sysdeps/unix/powerpc -I…/nptl/sysdeps/unix -I…/sysdeps/unix -I…/sysdeps/posix -I…/sysdeps/powerpc/powerpc64/cell -I…/sysdeps/powerpc/powerpc64 -I…/sysdeps/wordsize-64 -I…/sysdeps/powerpc/fpu -I…/nptl/sysdeps/powerpc -I…/sysdeps/powerpc -I…/sysdeps/ieee754/dbl-64 -I…/sysdeps/ieee754/flt-32 -I…/sysdeps/ieee754 -I…/sysdeps/generic/elf -I…/sysdeps/generic -I…/nptl -I… -I…/libio -I. -nostdinc -isystem /opt/toolchain/lib/gcc/powerpc64-linux/4.3.0/include -isystem /opt/toolchain/lib/gcc/powerpc64-linux/4.3.0/include-fixed -isystem /opt/toolchain/include -D_LIBC_REENTRANT -include …/include/libc-symbols.h -DASSEMBLER -o /home/user/glibc/bad-build/glibc64/string/memcpy.o -MD -MP -MF /home/user/glibc/bad-build/glibc64/string/memcpy.o.dt -MT /home/user/glibc/bad-build/glibc64/string/memcpy.o
在这一点上,我们可以简单地保存有问题的memcpy.o文件供以后使用。相反,我们希望使用这个片段来创建一个脚本,以便我们可以随意重新生成有问题的 memcpy.o 并将输出放置到一个 stage 目录中。
创建stage目录
> mkdir /home/user/stage/
从_make64_1中识别出memcpy.S的点开始,向后搜索术语“Entering”。每个 GLIBC 编译片段都使用源码的本地路径,因此您需要知道构建此特定文件时 shell 所在的源码目录。
make[2]: Entering directory `/home/user/glibc/bad-build/libc/string'
将此文件和之前确定的memcpy.o编译片段复制到stage 目录中名为memcpy.sh的文件中。您需要搜索和替换一些内容才能使其有用
- 将-o目标更改为stage 目录,即-o /home/user/stage/memcpy.o。
- 删除-M*标志。他们不需要了。
#!/bin/bash cd /home/user/glibc/bad-build/libc/string
/opt/toolchain/bin/gcc -m64 …/sysdeps/powerpc/powerpc64/cell/memcpy.S -c -I…/include -I/home/user/glibc/bad-build/glibc64/string -I/home/user/glibc/bad-build/glibc64 -I…/sysdeps/powerpc/powerpc64/elf -I…/sysdeps/powerpc/elf -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/cell/fpu -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/cell -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/fpu -I…/sysdeps/powerpc/powerpc64/fpu -I…/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64 -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64 -I…/sysdeps/unix/sysv/linux/wordsize-64 -I…/nptl/sysdeps/unix/sysv/linux/powerpc -I…/sysdeps/unix/sysv/linux/powerpc -I…/sysdeps/ieee754/ldbl-128ibm -I…/sysdeps/ieee754/ldbl-opt -I…/nptl/sysdeps/unix/sysv/linux -I…/nptl/sysdeps/pthread -I…/sysdeps/pthread -I…/sysdeps/unix/sysv/linux -I…/sysdeps/gnu -I…/sysdeps/unix/common -I…/sysdeps/unix/mman -I…/sysdeps/unix/inet -I…/nptl/sysdeps/unix/sysv -I…/sysdeps/unix/sysv -I…/sysdeps/unix/powerpc -I…/nptl/sysdeps/unix -I…/sysdeps/unix -I…/sysdeps/posix -I…/sysdeps/powerpc/powerpc64/cell -I…/sysdeps/powerpc/powerpc64 -I…/sysdeps/wordsize-64 -I…/sysdeps/powerpc/fpu -I…/nptl/sysdeps/powerpc -I…/sysdeps/powerpc -I…/sysdeps/ieee754/dbl-64 -I…/sysdeps/ieee754/flt-32 -I…/sysdeps/ieee754 -I…/sysdeps/generic/elf -I…/sysdeps/generic -I…/nptl -I… -I…/libio -I. -nostdinc -isystem /opt/toolchain/lib/gcc/powerpc64-linux/4.3.0/include -isystem /opt/toolchain/lib/gcc/powerpc64-linux/4.3.0/include-fixed -isystem /opt/toolchain/include -D_LIBC_REENTRANT -include …/include/libc-symbols.h -DASSEMBLER -o /home/user/stage/memcpy.o
从 stage 目录执??行这个脚本,你应该有一个生成的文件/home/user/stage/memcpy.o:
> cd /home/user/stage/
> sh memcpy.sh
将来如果您需要重新编写 memcpy.S并将其重新编译为memcpy.o只需:
> vim /home/user/glibc/bad-build/libc/sysdeps/powerpc/powerpc64/cell/memcpy.S
<make modifications>
> sh /home/user/stage/memcpy.sh
2.5. 生成脚本以链接有问题的 .o 文件以清理构建 test-memcpy
接下来的步骤将使用干净构建的make 检查日志_check64_1来查找并提取脚本片段,以便将干净构建的 test-memcpy 与有问题的 memcpy.o 重新链接,以便新的 test-memcpy 可以使用干净构建的加载器,但是使用坏的 memcpy 功能。这应该有助于我们确定 memcpy 中的错误所在的位置。
搜索测试程序test-memcpy.c的编译
/opt/toolchain/bin/gcc -m64 test-memcpy.c -c -std=gnu99 -O2 -Wall -Winline -Wwrite-strings -fmerge-all-constants -g -mlong-double-128 -mnew-mnemonics -Wstrict-prototypes -mlong-double-128 -I…/include -I/home/user/glibc/good-build/glibc64/string -I/home/user/glibc/good-build/glibc64 -I…/sysdeps/powerpc/powerpc64/elf -I…/sysdeps/powerpc/elf -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64/fpu -I…/sysdeps/powerpc/powerpc64/fpu -I…/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64 -I…/sysdeps/unix/sysv/linux/powerpc/powerpc64 -I…/sysdeps/unix/sysv/linux/wordsize-64 -I…/nptl/sysdeps/unix/sysv/linux/powerpc -I…/sysdeps/unix/sysv/linux/powerpc -I…/sysdeps/ieee754/ldbl-128ibm -I…/sysdeps/ieee754/ldbl-opt -I…/nptl/sysdeps/unix/sysv/linux -I…/nptl/sysdeps/pthread -I…/sysdeps/pthread -I…/sysdeps/unix/sysv/linux -I…/sysdeps/gnu -I…/sysdeps/unix/common -I…/sysdeps/unix/mman -I…/sysdeps/unix/inet -I…/nptl/sysdeps/unix/sysv -I…/sysdeps/unix/sysv -I…/sysdeps/unix/powerpc -I…/nptl/sysdeps/unix -I…/sysdeps/unix -I…/sysdeps/posix -I…/sysdeps/powerpc/powerpc64 -I…/sysdeps/wordsize-64 -I…/sysdeps/powerpc/fpu -I…/nptl/sysdeps/powerpc -I…/sysdeps/powerpc -I…/sysdeps/ieee754/dbl-64 -I…/sysdeps/ieee754/flt-32 -I…/sysdeps/ieee754 -I…/sysdeps/generic/elf -I…/sysdeps/generic -I…/nptl -I… -I…/libio -I. -nostdinc -isystem /opt/toolchain/lib/gcc/powerpc64-suse-linux/4.1.2/include -isystem /opt/toolchain/include -D_LIBC_REENTRANT -include …/include/libc-symbols.h -DPIC -DNOT_IN_libc=1 -o /home/user/glibc/good-build/glibc64/string/test-memcpy.o -MD -MP -MF /home/user/glibc/good-build/glibc64/string/test-memcpy.o.dt -MT /home/user/glibc/good-build/glibc64/string/test-memcpy.o
将test-memcpy.o复制到您的stage目录
> cp /home/user/glibc/good-build/glibc64/string/test-memcpy.o /home/user/stage
识别_check_64_1中的片段,该片段将 test-memcpy.o 与其余库链接并生成了test-memcpy可执行文件。
/opt/toolchain/bin/gcc -m64 -nostdlib -nostartfiles -o /home/user/glibc/good-build/glibc64/string/test-memcpy -Wl,-dynamic-linker=/lib64/ld64.so.1 -Wl,-z,combreloc -Wl,-z,relro /home/user/glibc/good-build/glibc64/csu/crt1.o /home/user/glibc/good-build/glibc64/csu/crti.o /opt/toolchain/bin/gcc -m64 --print-file-name=crtbegin.o /home/user/glibc/good-build/glibc64/string/test-memcpy.o -Wl,-rpath-link=/home/user/glibc/good-build/glibc64:/home/user/glibc/good-build/glibc64/math:/home/user/glibc/good-build/glibc64/elf:/home/user/glibc/good-build/glibc64/dlfcn:/home/user/glibc/good-build/glibc64/nss:/home/user/glibc/good-build/glibc64/nis:/home/user/glibc/good-build/glibc64/rt:/home/user/glibc/good-build/glibc64/resolv:/home/user/glibc/good-build/glibc64/crypt:/home/user/glibc/good-build/glibc64/nptl /home/user/glibc/good-build/glibc64/libc.so.6 /home/user/glibc/good-build/glibc64/libc_nonshared.a -lgcc -Wl,–as-needed -lgcc_s -Wl,–no-as-needed /opt/toolchain/bin/gcc -m64 --print-file-name=crtend.o /home/user/glibc/good-build/glibc64/csu/crtn.o
将此片段作为test-memcpy.sh保存到stage目录中。
在这一点上,我们想要将这个我们保存为test-memcpy.sh 的动态链接示例转换为一个脚本,该脚本静态链接到我们有问题的测试用例中。我们需要做几件事:
- 修改目标目的地为stage目录
- 设置-dynamic-linker路径以使用来自良好构建的动态链接器。
- 修改test-memcpy.o的路径,指向 stage 目录中的那个。
- 在test-memcpy.o文件之后,需要添加已保存到stage目录中的有问题的memcpy.o的路径。
- 将-rpath-link标志更改为-rpath标志。
#!/bin/bash /opt/toolchain/bin/gcc -m64 -nostdlib -nostartfiles -o /home/user/stage/test-memcpy -Wl,-dynamic-linker=/home/user/glibc/good-build/glibc64/elf/ld64.so.1 -Wl,-z,combreloc -Wl,-z,relro /home/user/glibc/good-build/glibc64/csu/crt1.o /home/user/glibc/good-build/glibc64/csu/crti.o /opt/toolchain/bin/gcc -m64 --print-file-name=crtbegin.o /home/user/stage/test-memcpy.o /home/user/stage/memcpy.o -Wl,-rpath=/home/user/glibc/good-build/glibc64: /home/user/glibc/good-build/glibc64/math:/home/user/glibc/good-build/glibc64/elf: /home/user/glibc/good-build/glibc64/dlfcn:/home/user/glibc/good-build/glibc64/nss: /home/user/glibc/good-build/glibc64/nis:/home/user/glibc/good-build/glibc64/rt: /home/user/glibc/good-build/glibc64/resolv:/home/user/glibc/good-build/glibc64/crypt: /home/user/glibc/good-build/glibc64/nptl /home/user/glibc/good-build/glibc64/libc.so /home/user/glibc/good-build/glibc64/libc_nonshared.a -lgcc -Wl,–as-needed -lgcc_s -Wl,–no-as-needed /opt/toolchain/bin/gcc -m64 --print-file-name=crtend.o /home/user/glibc/good-build/glibc64/csu/crtn.o
这应该已经创建了文件**/home/user/stage/test-memcpy**。
此时,您可以验证test-memcpy是否正在使用来自良好构建的加载器:
> readelf -l /home/user/stage/test-memcpy | grep INTERP -A 2
INTERP 0x0000000000000238 0x0000000010000238 0x0000000010000238
0x0000000000000045 0x0000000000000045 R 1
[Requesting program interpreter: /home/user/glibc/good-build/glibc64/elf/ld64]
如果您执行test-memcpy,您现在应该会看到段违规:
> ./test-memcpy
simple_memcpy builtin_memcpy memcpy
Length 1, alignment 0/ 0: 1 3 1
Length 1, alignment 0/ 0: 1 2 2
Length 1, alignment 0/ 0: 1 3 1
Length 1, alignment 0/ 0: 1 3 1
...
Length 496, alignment 31/ 0: 249 48 47
Length 496, alignment 0/31: 249 51 49
Length 496, alignment 31/31: 249 29 29
Length 4096, alignment 0/ 0: 2052 134 134
Didn't expect signal from child: got `Segmentation fault'
现在运行调试器并确保使用–direct标志运行。调试器会将–direct标志传递给 GLIBC测试框架,该框架将以标志为方向(direction)直接运行测试而不是立即fork函数。
> gdb64 test-memcpy
...
(gdb) run --direct
Starting program: /home/user/stage/test-memcpy --direct
warning: Breakpoint address adjusted from 0x100a1dd0 to 0x10000200.
simple_memcpy builtin_memcpy memcpy
Length 1, alignment 0/ 0: 2 4 2
Length 1, alignment 0/ 0: 2 4 2
Length 1, alignment 0/ 0: 2 4 2
...
Length 4096, alignment 0/ 0: 2052 135 137
Program received signal SIGSEGV, Segmentation fault.
0x000000001000188c in .memcpy ()
(gdb) bt
2.6. 识别有问题的代码,重新生成有问题的 mempcy.o 并重新链接
现在您可以调试有问题的代码,只需修改/home/user/stage/bad-build/libc/sysdeps/powerpc/powerpc64/cell/memcpy.S并重新运行 memcpy.sh 以及test-memcpy.sh。然后简单地重新运行 test-memcpy; 冲洗(rinse); 重复。
2.7. 动态链接最终可执行文件不起作用的角落案例
如果您无法让动态链接器正确链接memcpy.o和test-memcpy.o,您可能需要静态链接 .o 文件,尽管这是一个骇人听闻的解决方案。-rpath和-dynamic-linker方法是优选的。
- 添加 -static 标志
- 修改目标目的地为stage目录
- 设置-dynamic-linker路径以使用来自良好构建的动态链接器。
- 修改test-memcpy.o的路径,指向 stage 目录中的那个。
- 在test-memcpy.o文件之后,需要添加已保存到stage目录中的有问题的memcpy.o的路径。
- 将指向libc.so的链接更改为libc.a。
- 在 libc_nonshared.a 之后添加 dl-iteratephdr.o 的链接。
- 将-lgcc_s的链接更改为-lgcc_eh。
#!/bin/bash /opt/toolchain/bin/gcc -m64 -static -nostdlib -nostartfiles -o /home/user/stage/test-memcpy -Wl,-dynamic-linker=/home/user/glibc/good-build/glibc64/elf/ld64.so.1 -Wl,-z,combreloc -Wl,-z,relro /home/user/glibc/good-build/glibc64/csu/crt1.o /home/user/glibc/good-build/glibc64/csu/crti.o /opt/toolchain/bin/gcc -m64 --print-file-name=crtbegin.o /home/user/stage/test-memcpy.o /home/user/stage/memcpy.o -Wl,-rpath-link=/home/user/glibc/good-build/glibc64: /home/user/glibc/good-build/glibc64/math:/home/user/glibc/good-build/glibc64/elf: /home/user/glibc/good-build/glibc64/dlfcn:/home/user/glibc/good-build/glibc64/nss: /home/user/glibc/good-build/glibc64/nis:/home/user/glibc/good-build/glibc64/rt: /home/user/glibc/good-build/glibc64/resolv:/home/user/glibc/good-build/glibc64/crypt: /home/user/glibc/good-build/glibc64/nptl /home/user/glibc/good-build/glibc64/libc.a /home/user/glibc/good-build/glibc64/libc_nonshared.a /home/user/glibc/good-build/glibc64/elf/dl-iteratephdr.o -lgcc -Wl,–as-needed -lgcc_eh -Wl,–no-as-needed /opt/toolchain/bin/gcc -m64 --print-file-name=crtend.o home/user/glibc/good-build/glibc64/csu/crtn.o
注意:在前面的调用中,整个 -rpath-link 都在一行上,没有换行符。
3. GLIBC 搜索顺序
GLIBC 源文件和头文件搜索顺序保存在配置输出中。这首先由操作系统和平台决定,其次由depth决定,第三由 Implies 文件决定,第四由 Subdirs 文件决定。
4. 强制 GCC 生成用于检查宏扩展的中间输出
使用 -dD -E 或 --save-temps
|