问题描述
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!".在屏幕上(标准输出).使用
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
(编者注:或 gdb ./hello
对其进行调试/单步执行.这就是为什么我们使用 nasm -g -Fdwarf
和 gcc -g
.或在GDB中使用 layout reg
进行不依赖调试符号的反汇编和注册视图,请参见https://stackoverflow.com/tags/x86/info )
(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
仅打印"Hello,World!"和声明
just to print "Hello, World!" and the statement
_start:
以上!是主要功能吗?
和声明
int 0x80
为什么要使用它?你们能给我深入介绍一下该程序的基本原理吗.
why is it used at all? Can you guys give me a deep explaination of the basic working of this program.
推荐答案
在机器代码中,没有任何功能.至少,处理器对功能一无所知.程序员可以根据自己的喜好来构造其代码. _start
是称为 symbol 的名称,它只是程序中某个位置的名称.符号用于表示您不知道其地址的位置.它们在链接过程中已解决.符号 _start
用作进入点(请参见此答案),这是操作系统跳转到启动程序的位置.除非您通过其他方式指定入口点,否则每个程序都必须包含 _start
.程序使用的其他符号是 msg
,链接器将其解析为字符串 Hello,world!
所在的地址和 len
是 msg
的长度.
In machine code, there are no functions. At least, the processor knows nothing about functions. The programmer can structure his code as he likes. _start
is something called a symbol which is just a name for a location in your program. Symbols are used to refer to locations whose address you don't know yet. They are resolved during linking. The symbol _start
is used as the entry point (cf. this answer) which is where the operating system jumps to start your program. Unless you specify the entry point by some other way, every program must contain _start
. The other symbols your program uses are msg
, which is resolved by the linker to the address where the string Hello, world!
resides and len
which is the length of msg
.
程序的其余部分执行以下操作:
The rest of the program does the following things:
- 设置系统调用
write(1,msg,len)
的寄存器.write
具有系统调用号4,该系统调用号存储在eax
中,以使操作系统知道您想要系统调用4.此系统调用将数据写入文件.提供的文件描述符号为1,代表标准输出. - 使用
int $ 0x80
执行系统调用.该指令将中断您的程序,操作系统将接管该程序并执行其编号存储在eax
中的功能.就像调用OS内核的函数调用一样.调用约定与其他函数不同,在寄存器中传递了args. - 设置系统调用
_exit(?)
的寄存器.它的系统呼叫号码是1,该号码进入eax
.可悲的是,该代码忘记为_exit
设置参数,该参数应为0表示成功.取而代之的是使用之前ebx
中的内容,似乎是1. - 使用
int $ 0x80
执行系统调用.因为_exit
结束了程序,所以它不返回.您的程序到此结束.
- Set up the registers for the system call
write(1, msg, len)
.write
has system call number 4 which is stored ineax
to let the operating system know you want system call 4. This system call writes data to a file. The file descriptor number supplied is 1 which stands for standard output. - Perform a system call using
int $0x80
. This instruction interrupts your program, the operating system picks this up and performs the function whose number is stored ineax
. It's like a function call that calls into the OS kernel. The calling convention is different from other functions, with args passed in registers. - Set up the registers for the system call
_exit(?)
. Its system call number is 1 which goes intoeax
. Sadly, the code forgets to set the argument for_exit
, which should be 0 to indicate success. Instead, whatever was inebx
before is used instead, which seems to be 1. - Perform a system call using
int $0x80
. Because_exit
ends the program, it does not return. Your program ends here.
指令 db
告诉汇编器将以下数据放入程序中当前所在的位置.这会将字符串 Hello,world!
后面跟换行符放入程序中,因此我们可以告诉 write
系统调用编写该字符串.
The directive db
tells the assembler to place the following data into the program where we currently are. This places the string Hello, world!
followed by a newline into the program so we can tell the write
system call to write that string.
行 len equ $-msg
告诉汇编程序,而不是 len
是 $
(我们目前所在的位置)和 msg
之间的区别.定义了它,以便我们可以将要打印的文本传递给 write
多久.
The line len equ $ - msg
tells the assembler than len
is the difference between $
(where we currently are) and msg
. This is defined so we can pass to write
how long the text we want to print is.
程序中分号(;
)之后的所有内容都是一个注释,被汇编程序忽略.
Everything after a semicolon (;
) in the program is a comment ignored by the assembler.
这篇关于使用来自_start的32位int 0x80 Linux系统调用来解释此x86 Hello World是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!