如何使用ld手动运行产生elf可执行文件? [英] How to run manually produce an elf executable using ld?

查看:222
本文介绍了如何使用ld手动运行产生elf可执行文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设法弄清生成可执行文件时链接过程的工作方式.为此,我正在阅读伊恩·泰勒(Ian Taylor)的博客系列,但其中有很多目前,它还超出了我的范围-所以我想看看它在实践中是如何工作的.

I'm trying to get my head around how the linking process works when producing an executable. To do that I'm reading Ian Taylor's blog series about it, but a lot of it is beyond me at the moment - so I'd like to see how it works in practice.

此刻,我生成了一些目标文件,并通过gcc将它们链接为:

At the moment I produce some object files and link them via gcc with:

gcc -m32 -o test.o -c test.c
gcc -m32 -o main.o -c main.c
gcc -m32 -o test main.o test.o

如何使用 ld 复制 gcc -m32 -o test main.o test.o 阶段?

我尝试了一个非常幼稚的方法: ld -A i386 ./test.o ./main.o

I've tried a very naive: 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 添加它们?

I'm most confused by _start and _GLOBAL_OFFSET_TABLE_ being missing - what additional info does gcc give to ld to add them?

以下是文件:

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");
}

推荐答案

@sam:由于我是编译初学者,所以我不是回答您问题的最佳人选.我知道如何编译程序,但我并不真正理解所有细节( https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools )因此,我今年决定尝试了解编译的工作原理,并且我尝试或多或少地执行了几天前所做的相同工作.由于没有人回答,我将公开我所做的事情,但我希望专家会补充我的回答.

@sam : I am not the best people to answer your question because I am a beginner in compilation. I know how to compile programs but I do not really understand all the details (https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools) So, I decided this year to try to understand how compilation works and I tried to do, more or less, the same things as you tried a few days ago. As nobody has answered, I am going to expose what I have done but I hope an expert will supplement my answer.

简短的回答:建议不要直接使用ld,而应直接使用gcc.然而,正如您所写,知道链接过程是如何工作的还是很有趣的.此命令在我的计算机上有效:
ld -m elf_i386-动态链接器/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

Short answer : It is recommended to not use ld directly but to use gcc directly instead. Nevertheless, it is, as you write, interesting to know how the linking process works. This command works on my computer :
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测试main.o test.o

Very Long answer :
How did I find the command above ?
As n.m suggested, run gcc with -v option.
gcc -v -m32 -o test main.o test.o

...
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 ...(很多选项和参数)
....

...
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 ... (many options and parameters)
....

如果使用这些选项和参数(复制和粘贴)运行ld,它应该可以工作.
尝试使用-m elf_i386命令(请参阅collect2参数)
ld -m elf_i386 test.o main.o

If you run ld with these options and parameters (copy and paste), it should work.
Try your command with -m elf_i386 (cf. collect2 parameters)
ld -m elf_i386 test.o main.o

ld:警告:找不到条目符号_start;....

ld: warning: cannot find entry symbol _start; ....

在完整ld命令中使用的目标文件中查找符号_start.
readelf -s/usr/lib/crt1.o (或objdump -t)

Look for symbol _start in object files used in the full ld command.
readelf -s /usr/lib/crt1.o (or objdump -t)

符号表'.symtab'包含18个条目:
数字:值大小类型绑定Vis Ndx名称
...
11:00000000 0 FUNC全局默认值2 _开始

Symbol table '.symtab' contains 18 entries:
Num: Value Size Type Bind Vis Ndx Name
...
11: 00000000 0 FUNC GLOBAL DEFAULT 2 _start

将此对象添加到您的ld命令中:
ld -m elf_i386 test.o main.o/usr/lib/crt1.o

Add this object to your ld command :
ld -m elf_i386 test.o main.o /usr/lib/crt1.o

...对`__libc_csu_fini'的未定义引用...

... undefined reference to `__libc_csu_fini'...

在目标文件中查找此新引用.由于-L,-l选项以及某些.so包含其他库,因此知道使用哪个库/目标文件并不是很明显.例如, cat/usr/lib/libc.so .但是,带有--trace选项的ld会有所帮助.尝试以下命令
ld --trace ...(collect2参数)
最后,您应该找到
ld -m elf_i386 -o test test.omain.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.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函数( https://gcc.gnu.org/onlinedocs/gccint/Initialization.html ).添加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

Look for this new reference in object files. It is not so obvious to know which library/object files are used because of -L, -l options and some .so include other libraries. For example, cat /usr/lib/libc.so. But, ld with --trace option helps. Try this command
ld --trace ... (collect2 parameters)
At the end, you should find
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
or shorter (cf. 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
It compiles but it does not run (Try to run ./test). It needs the right -dynamic-linker option because it is a dynamically linked ELF executable. (cf collect2 parameters to find it)
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
But, it does not run (Segmentation fault (core dumped)) because you need the epilogue of the _init and _fini functions (https://gcc.gnu.org/onlinedocs/gccint/Initialization.html). Add the ctrn.o object.
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

你好,世界

这篇关于如何使用ld手动运行产生elf可执行文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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