【问题标题】:What is the explanation of this x86 Hello World using 32-bit int 0x80 Linux system calls from _start?这个 x86 Hello World 使用来自 _start 的 32 位 int 0x80 Linux 系统调用的解释是什么?
【发布时间】:2017-07-12 08:20:04
【问题描述】:
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 -Fdwarf 和gcc -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

只是为了打印“Hello, World!”和声明

_start:

以上!是main函数吗?

和声明

int 0x80

为什么要使用它?你们能不能给我详细解释一下这个程序的基本工作原理。

【问题讨论】:

  • 您似乎缺乏 Linux 的基础知识,或者一般来说,缺乏汇编编程。一本书或在线教程可能更合适:-) 这里唯一的汇编特定方面是权限转移(系统调用),现在已经过时的 32 位,int 0x80。程序的其余部分只是设置作为程序员的任何编程语言所期望的参数。
  • “起初神创造天地”……我们应该从哪里开始呢? @MargaretBloom 完全正确,请尝试寻找一个好的教程
  • 请给我一些建议?
  • “就像所有这些指令只需要打印“Hello, World!” ...实际上这部分几乎什么都不做,你好世界的肉在这种情况下,打印指令隐藏在操作系统中。如果这是一些旧的 8 位计算机示例,通过直接将值写入视频 RAM 并设置视频芯片来显示它们,在屏幕上创建“Hello, World”,那么代码将涉及更多指令和更复杂的逻辑,此外,您还需要每个字母的“字体”像素数据等......这就像“嘿操作系统,为我打印 Hello world。”工作“努力”。跨度>
  • 相关:Hello, world in assembly language with Linux system calls? 使用 32 位 int 0x80 系统调用获得完整注释的“Hello World”。还 another answer 使用 libc 中的 puts 而不是直接系统调用。

标签: linux assembly x86 nasm


【解决方案1】:

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

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

  1. 为系统调用write(1, msg, len) 设置寄存器。 write 的系统调用号 4 存储在 eax 中,让操作系统知道您需要系统调用 4。此系统调用将数据写入文件。提供的文件描述符编号为 1,代表标准输出。
  2. 使用int $0x80 执行系统调用。该指令会中断您的程序,操作系统会选择它并执行其编号存储在eax 中的功能。这就像调用操作系统内核的函数调用。调用约定与其他函数不同,with args passed in registers.
  3. 为系统调用_exit(?) 设置寄存器。它的系统调用号是 1,进入eax。遗憾的是,代码忘记为_exit 设置参数,该参数应为0 表示成功。相反,使用之前在 ebx 中的任何内容,这似乎是 1。
  4. 使用int $0x80 执行系统调用。因为_exit 结束了程序,所以它没有返回。您的程序到此结束。

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

len equ $ - msg 行告诉汇编程序而不是len is the difference between $ (where we currently are) and msg。这是定义的,因此我们可以将要打印的文本传递给write。

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

【讨论】:

  • @PeterCordes 请不要只是将随机问题链接转储到答案中。这看起来超级难看。
  • 我有点喜欢在问题文本中加入问题标题,尤其是当它是描述问答内容的有用标题时。但也只是为了让我能认出它是我以前见过或没见过的。不过,对不起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 2015-03-19
  • 2021-12-26
相关资源
最近更新 更多