What is the explanation of this x86 Hello World using 32-bit int 0x80 Linux system calls from _start?

时间:2017-07-12 08:20:05

标签: linux assembly x86 nasm

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

This is a basic 32-bit x86 Linux assembly code to print "Hello, World!" on the screen (standard output). Build + run it with

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

(Editor's note: or gdb ./hello to debug / single-step it. That's why we used nasm -g -Fdwarf and gcc -g. Or use layout reg inside GDB for disassembly+register view that doesn't depend on debug symbols. See the bottom of https://stackoverflow.com/tags/x86/info)


Now I want to ask about how is this code working behind the scenes. Like what is the need for all these instructions

_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

just to print "Hello, World!" and the statement

_start:

above! Is it the main function?

and the statement

int 0x80

why is it used at all? Can you guys give me a deep explaination of the basic working of this program.

1 个答案:

答案 0 :(得分:10)

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

该计划的其余部分做了以下事情:

  1. 设置系统调用write(1, msg, len)的寄存器。 write具有系统调用号4,存储在eax中以让操作系统知道您想要系统调用4.此系统调用将数据写入文件。提供的文件描述符编号为1,表示标准输出。
  2. 使用int $0x80执行系统调用。该指令会中断您的程序,操作系统会选择该程序并执行其编号存储在eax中的功能。这就像调用OS内核的函数调用。调用约定与其他函数with args passed in registers.
  3. 不同
  4. 设置系统调用_exit(?)的寄存器。其系统呼叫号码为1,进入eax。遗憾的是,代码忘记设置_exit的参数,该参数应该为0表示成功。相反,之前使用的ebx中的任何内容都会被使用,这似乎是1。
  5. 使用int $0x80执行系统调用。因为_exit结束程序,所以它不会返回。你的课程在这里结束。
  6. 指令db告诉汇编程序将以下数据放入我们当前所在的程序中。这会将字符串Hello, world!后跟换行符放入程序中,这样我们就可以告诉write系统调用写入该字符串。

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

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