简体   繁体   English

如果一个 object 文件定义了 _start 并且不使用任何库,为什么我还需要链接它才能执行它?

[英]If an object file defines _start and doesn't use any libraries, why do I still need to link it before I can execute it?

I have a hello world program:我有一个 hello world 程序:

.global _start

.text

_start:
    # write (1, msj, 13)
    mov $1, %rax            # system call 1 is write
    mov $1, %rdi            # file handler 1 is stdout
    mov $message, %rsi      # address of string to output
    mov $13, %rdx           # number of bytes
    syscall

    # exit(0)
    mov $60, %rax           # system call 60 is exit
    xor %rdi, %rdi          # we want to return code 0
    syscall

message:
    .ascii "Hello, world\n"

I can assemble this into an object file with:我可以将它组装成一个 object 文件:

as hello.s -o hello.o

This object file is not executable.此 object 文件不可执行。 When I try to execute it, I get:当我尝试执行它时,我得到:

bash: ./hello.o: cannot execute binary file: Exec format error

I need to invoke the linker to make this viable:我需要调用 linker 以使其可行:

ld hello.o -o hello

At this point, the hello program works.至此, hello程序开始工作了。 However, the use of the linker here is confusing to me.... I'm not linking in any external libraries.但是,在这里使用 linker 让我感到困惑......我没有在任何外部库中链接。 I seem to just be linking the object file to nothing.我似乎只是将 object 文件链接到任何内容。

What is the linker doing for such a "self-contained" program? linker 为这样一个“自成一体”的程序做了什么?

ELF files have different types, like ELFTYPE_EXEC (traditional non-PIE executable) or ELFTYPE_REL (relocatable object file, normally with a .o filename). ELF 文件有不同的类型,例如 ELFTYPE_EXEC(传统的非 PIE 可执行文件)或 ELFTYPE_REL(可重定位的 object文件,通常使用.o文件名)。

as doesn't have a special-case mode that outputs an executable instead of an object file. as没有输出可执行文件而不是 object 文件的特殊情况模式。 There are other assemblers, or at least one: FASM, that do have a special mode to output an ELF executable directly.还有其他汇编器,或者至少一个:FASM,它们确实有一个特殊模式,可以直接执行 ELF 可执行文件 output。

Given the ELF object file that as produces, you could: as生成的 ELF object 文件,您可以:

  • link it into a simple static executable like you're doing将它链接到一个简单的 static 可执行文件中,就像你正在做的那样
  • link it into a PIE executable将其链接到 PIE 可执行文件中
  • link it into a dynamic executable, possibly even one that links some .so shared libraries;将其链接到动态可执行文件中,甚至可能链接一些.so共享库; those could have static constructors (init functions) that run before your _start .那些可能有在_start之前运行的 static 构造函数(初始化函数)。 (For example glibc's libc.so does this, which is why it happens to work to call libc functions from _start on Linux without manually calling glibc init functions, if you dynamically link.) (例如 glibc 的libc.so就是这样做的,这就是为什么它恰好可以从 Linux 上的_start调用 libc 函数而无需手动调用 glibc 初始化函数,如果你动态链接的话。)

The .o needs to be linked because no absolute address has been chosen for it to be loaded at, to fill in things like your 64-bit absolute immediate in mov $message, %rsi . .o需要链接,因为没有选择绝对地址来加载它,以在mov $message, %rsi中填写诸如 64 位绝对立即数之类的内容。

(If you'd use lea message(%rip), %rsi the code would be position-independent but the distance between the .text and .rodata sections wouldn't be known yet. Although you put your string right in .text so that would get resolved at assemble time if you hadn't chosen the least efficient way to get an address into a register, so that would give you a stand-alone block of code+data. But the most efficient way, mov $message, %esi , would also need an absolute (32-bit) address.) (如果您使用lea message(%rip), %rsi代码将与位置无关,但.text.rodata部分之间的距离尚不清楚。尽管您将字符串正确放入.text所以如果您没有选择效率最低的方法将地址放入寄存器,那么这将在汇编时得到解决,这样会给您一个独立的代码+数据块。但最有效的方法是mov $message, %esi ,还需要一个绝对(32 位)地址。)

as doesn't know what you want to do, and GNU Binutils was primarily written for use by compiler back-ends, so there was no point making as more complicated to be able to write an ELF-type EXEC file directly since that's what ld is for. as不知道你想做什么,而且 GNU Binutils 主要是为编译器后端编写的,所以直接编写 ELF 类型的EXEC文件没有意义, as这就是ld是为了。 This is the Unix philosophy of making small separate tools that do one thing well.这就是 Unix 的理念,即制作能够做好一件事的小型独立工具。

If you want to assemble + link with one command, make a shell script, or use a compiler front-end:如果你想用一个命令组装 + 链接,制作一个 shell 脚本,或者使用编译器前端:

gcc -nostdlib -static -no-pie start.s -o static_executable

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法链接 object 文件所以我不能让它执行 - unable to link object file so i can't make it executalbe 如果我使用调用,实模式中断有效,如果我使用 INT,则无效(不会执行) - Real mode interrupt works if I use call, doesn't work(won't execute) if I use INT 为什么我的代码不发出蜂鸣声,以及我用Enter退出什么代码 - Why doesn't my code Beep And what code do i use to exit with enter 如何在汇编程序中使用C库? - How do I use C libraries in assembler? 我可以动态链接具有重复功能名称的库吗? - Can I dynamically link libraries that have duplicated name of functions? 为什么我需要在syscall读取之前调用syscall write以使其接受用户输入? - Why do i need to call syscall write before syscall read to make it accept user input? 如何链接从 C 代码生成的目标文件、静态库和 NASM 生成的目标文件? - How do I link an object file generated from C code, a static library and a NASM generated object file? linux'无法在我编译的每个可执行文件上执行二进制文件',chmod 777没有帮助 - linux 'cannot execute binary file' on every executable I compile, chmod 777 doesn't help 如何让Cython使用目标文件? - How do I get Cython to use an object file? 为什么需要口罩说明? - Why do I need the mask instruction?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM