汇编程序如何工作?

发布于 2024-11-10 11:23:39 字数 119 浏览 3 评论 0原文

我正在寻找有关在生成机器代码时使用汇编器的简要描述。

所以我知道汇编是机器代码的 1:1 翻译。但我对目标代码和链接器以及它们如何放入其中感到困惑。

我不需要复杂的答案,一个简单的答案就可以了

I am looking for a brief description of the use of an assembler in producing machine code.

So I know that assembly is a 1:1 translation of machine code. But I am getting confused about object code and linkers and how they place into it.

I don't need a complex answer just a simple one will do fine

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

伪装你 2024-11-17 11:23:39

汇编器和编译器都将源文件翻译成目标文件。

目标文件实际上是最终可执行输出(由链接器生成)之前的中间步骤。

链接器获取指定的目标文件和库(它们是目标文件的包)并解析重定位(或“修复”)记录。

当编译器/汇编器不知道源代码中使用的函数或变量的地址时,会生成这些重定位记录,并按名称生成对其的引用,该引用可以由链接器解析。

例如,假设您希望程序将一条消息打印到屏幕上,分为两个源文件,并且您希望单独组装它们并链接它们(例如使用 Linux x86-64 系统调用) -

main.asm :

bits 64
section .text
extern do_message
global _start
_start:
    call do_message
    mov rax, 1
    int 0x80 

message.asm :

bits 64
section .text
global do_message
do_message:
    mov rdi, message
    mov rcx, dword -1
    xor rax, rax
    repnz scasb
    sub rdi, message
    mov rax, 4
    mov rbx, 1
    mov rcx, message
    mov rdx, rdi
    int 0x80
    ret

section .data
message: db "hello world",10,0

如果您组装这些并查看 main.asm 的目标文件输出(例如 objdump -d main.o),您会注意到“call do_message”的地址为 00 00 00 00 - 无效。

0000000000000000 <_start>:
   0:   e8 00 00 00 00          callq  5 <_start+0x5>
   5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
   c:   cd 80                   int    $0x80

但是,为地址的 4 个字节创建了重定位记录:

$ objdump -r main.o
main.o:     file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE 
0000000000000001 R_X86_64_PC32     do_message+0xfffffffffffffffc
000000000000000d R_X86_64_32       .data

偏移量为“1”,类型为“R_X86_64_PC32”,告诉链接器解析此引用,并将解析后的地址放入指定的偏移量中。

当您将最终程序与“ld -o program main.o message.o”链接时,所有重定位都已解决,如果没有任何问题未解决,则留下可执行文件。

当我们“objdump -d”可执行文件时,我们可以看到解析的地址:

00000000004000f0 <_start>:
  4000f0:   e8 0b 00 00 00          callq  400100 <do_message>
  4000f5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
  4000fc:   cd 80                   int    $0x80

相同类型的重定位用于变量和函数。
当您将程序链接到多个大型库(例如 libc)时,会发生相同的过程 - 您定义一个名为“main”的函数,libc 有一个外部引用 - 然后 libc 在您的程序之前启动,并在以下情况下调用您的“main”函数您运行可执行文件。

Both an assembler and a compiler translate source files into object files.

Object files are effectively an intermediate step before the final executable output (generated by the linker).

The linker takes the specified object files and libraries (which are packages of object files) and resolves relocation (or 'fixup') records.

These relocation records are made when the compiler/assembler doesn't know the address of a function or variable used in the source code, and generates a reference for it by name, which can be resolved by the linker.

For example, say you want a program to print a message to the screen, seperated into two source files, and you want to assemble them seperately and link them (example using Linux x86-64 syscalls) -

main.asm :

bits 64
section .text
extern do_message
global _start
_start:
    call do_message
    mov rax, 1
    int 0x80 

message.asm :

bits 64
section .text
global do_message
do_message:
    mov rdi, message
    mov rcx, dword -1
    xor rax, rax
    repnz scasb
    sub rdi, message
    mov rax, 4
    mov rbx, 1
    mov rcx, message
    mov rdx, rdi
    int 0x80
    ret

section .data
message: db "hello world",10,0

If you assemble these and look at the object file output of main.asm (eg, objdump -d main.o), you will notice the 'call do_message' has an address of 00 00 00 00 - which is invalid.

0000000000000000 <_start>:
   0:   e8 00 00 00 00          callq  5 <_start+0x5>
   5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
   c:   cd 80                   int    $0x80

But, a relocation record is made for the 4 bytes of the address :

$ objdump -r main.o
main.o:     file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE 
0000000000000001 R_X86_64_PC32     do_message+0xfffffffffffffffc
000000000000000d R_X86_64_32       .data

The offset is '1' and the type is 'R_X86_64_PC32' which tells the linker to resolve this reference, and put the resolved address into the specified offset.

When you link the final program with 'ld -o program main.o message.o', the relocations are all resolved, and if nothing is unresolved, you are left with an executable.

When we 'objdump -d' the executable, we can see the resolved address :

00000000004000f0 <_start>:
  4000f0:   e8 0b 00 00 00          callq  400100 <do_message>
  4000f5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
  4000fc:   cd 80                   int    $0x80

The same kind of relocations are used for variables as well as functions.
The same process happens when you link your program against multiple large libraries, such as libc - you define a function called 'main' which libc has an external reference to - then libc is started before your program, and calls your 'main' function when you run the executable.

醉生梦死 2024-11-17 11:23:39

简单解释:

一旦汇编语言被汇编成目标代码,链接器就用于将目标代码转换为计算机可以理解和运行的可执行命令。生成的机器码可以由CPU的控制器解释。

Simple explanation:

Once the assembly language is assembled into object code, the linker is used to convert the object code into an executable of commands that the computer can understand and run. The generated machine code can be interpreted by the cpu's controller.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文