我正在努力弄清生成可执行文件时链接过程的工作方式。为此,我正在阅读Ian Taylor's blog series,但目前还很多,所以我想看看它如何在实践中起作用。
此刻,我生成一些目标文件,并通过gcc将它们链接:
gcc -m32 -o test.o -c test.c
gcc -m32 -o main.o -c main.c
gcc -m32 -o test main.o test.o
如何使用gcc -m32 -o test main.o test.o
复制ld
阶段?
我已经尝试过非常幼稚:ld -A i386 ./test.o ./main.o
但这会返回这些错误:
ld: i386 architecture of input file `./test.o' is incompatible with i386:x86-64 output
ld: i386 architecture of input file `./main.o' is incompatible with i386:x86-64 output
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
./test.o: In function `print_hello':
test.c:(.text+0xd): undefined reference to `_GLOBAL_OFFSET_TABLE_'
test.c:(.text+0x1e): undefined reference to `puts'
./main.o: In function `main':
main.c:(.text+0x15): undefined reference to `_GLOBAL_OFFSET_TABLE_
我对_start
和_GLOBAL_OFFSET_TABLE_
的丢失感到困惑-gcc
给ld
提供了哪些附加信息来添加它们?
以下是文件:
main.c
#include "test.h"
void main()
{
print_hello();
}
test.h
void print_hello();
test.c
#include <stdio.h>
void print_hello()
{
puts("Hello, world");
}
答案 0 :(得分:1)
@sam:因为我是汇编的初学者,所以我不是回答您问题的最佳人选。我知道如何编译程序,但我不太了解所有细节(https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools) 因此,我今年决定尝试了解编译的工作原理,并且我尝试或多或少地执行了几天前的尝试。由于没有人回答,我将公开我所做的事情,但我希望专家会补充我的回答。
简短的回答:建议不要直接使用ld,而应直接使用gcc。然而,正如您所写,了解链接过程的工作方式很有趣。此命令在我的计算机上有效:
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o /usr/lib/crtn.o
很长的答案:
我如何找到上面的命令?
按照n.m的建议,使用-v选项运行gcc。
gcc -v -m32 -o test main.o test.o
...
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 ...(很多 选项和参数)
....
如果使用这些选项和参数(复制和粘贴)运行ld,它应该可以工作。
尝试使用-m elf_i386命令(参见collect2参数)
ld -m elf_i386 test.o main.o
ld:警告:找不到条目符号_start; ....
在完整ld命令中使用的目标文件中查找符号_start。
readelf -s /usr/lib/crt1.o
(或objdump -t)
符号表'.symtab'包含18个条目:
数值:值大小 类型Bind Vis Ndx名称
...
11:00000000 0 FUNC 全局默认值2 _开始
将此对象添加到您的ld命令中:
ld -m elf_i386 test.o main.o /usr/lib/crt1.o
...对`__libc_csu_fini'的未定义引用...
在目标文件中查找此新引用。由于-L,-l选项以及某些.so包含其他库,因此知道使用哪个库/目标文件并不是很明显。例如,cat /usr/lib/libc.so
。但是,带有--trace选项的ld会有所帮助。尝试以下命令
ld --trace ... (collect2 parameters)
最后,您应该找到
ld -m elf_i386 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc_nonshared.a /lib/libc.so.6 /usr/lib/crti.o
或更短(请参见cat /usr/lib/libc.so )
ld -m elf_i386 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o
它可以编译,但不能运行(尝试运行./test)。它需要正确的-dynamic-linker选项,因为它是动态链接的ELF可执行文件。 (请参见collect2参数进行查找)
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o
但是,由于您需要_init和_fini函数的结尾({{3 }})。添加ctrn.o对象。
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o /usr/lib/crtn.o
./test
你好,世界