这个x86 Hello World使用来自_start的32位int 0x80 Linux系统调用的解释是什么?


section .text
global _start       ;must be declared for using gcc
_start:                     ;tell linker entry point
mov edx, len    ;message length
mov ecx, msg    ;message to write
mov ebx, 1      ;file descriptor (stdout)
mov eax, 4      ;system call number (sys_write)
int 0x80        ;call kernel
mov eax, 1      ;system call number (sys_exit)
int 0x80        ;call kernel
section .data
msg db  'Hello, world!',0xa ;our dear string
len equ $ - msg         ;length of our dear string

这是一个基本的 32 位 x86 Linux 汇编代码,用于在屏幕上打印"Hello, World!"(标准输出(。 构建 + 运行它

nasm -felf -g -Fdwarf hello.asm
gcc -g -m32 -nostdlib -static -o hello hello.o
./hello

(编者注:或gdb ./hello调试/单步执行。 这就是为什么我们使用nasm -g -Fdwarfgcc -g. 或者使用 GDB 内部的layout reg进行不依赖于调试符号的反汇编+寄存器视图。 见 https://stackoverflow.com/tags/x86/info 底部(


现在我想问一下这段代码是如何在幕后工作的。就像所有这些说明的需要是什么

_start:                     ;tell linker entry point
mov edx, len    ;message length
mov ecx, msg    ;message to write
mov ebx, 1      ;file descriptor (stdout)
mov eax, 4      ;system call number (sys_write)
int 0x80        ;call kernel
mov eax, 1      ;system call number (sys_exit)
int 0x80        ;call kernel

只是为了打印"你好,世界!"和声明

_start:

以上!是主要功能吗?

和声明

int 0x80

为什么要使用它?你们能给我一个关于这个程序的基本工作的深入解释吗?

在机器代码中,没有函数。至少,处理器对功能一无所知。程序员可以随心所欲地构建他的代码。_start是一种称为符号的东西,它只是程序中某个位置的名称。符号用于指代您还不知道其地址的位置。它们在链接期间解析。符号_start用作入口点(参见此答案(,这是操作系统跳转以启动程序的位置。除非通过其他方式指定入口点,否则每个程序都必须包含_start。程序使用的其他符号是msg,它由链接器解析为字符串Hello, world!所在的地址,lenmsg的长度。

程序的其余部分执行以下操作:

  1. 设置系统调用write(1, msg, len)的寄存器。write具有存储在eax中的系统调用编号 4,以使操作系统知道您想要系统调用 4。此系统调用将数据写入文件。提供的文件描述符编号为 1,代表标准输出。
  2. 使用int $0x80执行系统调用。此指令会中断您的程序,操作系统会拾取它并执行其编号存储在eax中的功能。 这就像调用操作系统内核的函数调用。 调用约定与其他函数不同,参数在寄存器中传递。
  3. 设置系统调用_exit(?)的寄存器。它的系统呼叫号码是 1,进入eax.可悲的是,代码忘记为_exit设置参数,它应该为 0 表示成功。取而代之的是,使用之前ebx中的任何内容,这似乎是 1。
  4. 使用int $0x80执行系统调用。由于_exit结束程序,因此它不会返回。您的程序到此结束。

指令db告诉汇编程序将以下数据放入我们当前所在的程序中。这会将字符串Hello, world!后跟换行符放入程序中,以便我们可以告诉write系统调用写入该字符串。

len equ $ - msg告诉汇编程序的行比len$(我们目前所在的位置(和msg之间的区别。这是这样定义的,因此我们可以向write传递我们要打印的文本有多长。

程序中分号(;(之后的所有内容都是汇编程序忽略的注释

最新更新