先来一段能够输出“Hello, World”的汇编代码:
section .datastringShowing db "Hello, World",10,0stringShowingLength equ 13
section .bss
section .textglobal mainmain:push rbpmov rbp,rspmov rax,1mov rdi,1mov rsi,stringShowingmov rdx,stringShowingLengthsyscallmov rsp,rbppop rbpmov rax,60mov rdi,0syscall
nasm -f elf64 -g -F dwarf helloworld.asm -o helloworld.o
使用64位汇编器进行汇编。
gcc -o helloworld helloworld.o
进行链接。
./helloworld
进行执行。
下边进行代码的分解:
push rbp
mov rbp,rsp
这两段代码相当于把父程序调用子程序的栈保存下来,方便再回到父程序。
mov rax,1
寄存器 rax 中存放系统调用号,在其他情况下,返回值也存放在 eax 中。这段汇编代码表明让rax=1,表明会使用write(int fd,char *buf,int n)
系统调用,可以看到这个系统调用需要传入3个参数,第一个参数是文件描述符,0表示标准输入,1表示标准输出,2表示标准错误;第2个参数是读入的字符数组;第三个参数是要传输的字节数。
mov rdi,1mov rsi,stringShowingmov rdx,stringShowingLength
往write(int fd,char *buf,int n)
系统调用传递参数,当系统调用参数小于等于6个时,参数则必须按顺序放到寄存器rdi
,rsi
,rdx
,r10
,r8
,r9
中。当系统调用参数大于6个时,全部参数应该依次放在一块连续的内存区域里,同时在寄存器rbx
中保存指向该内存区域的指针。可以看到在这段代码中rdi放入的是文件描述符——1,代表标准输出,rsi
中放入的是stringShowing
这个字符串的首字母地址,rdx
放入的是stringShowing
的长度stringShowingLength
,为13。
syscall
就是真正系统调用。
mov rsp,rbp
pop rbp
把堆栈还原。
mov rax,60
mov rdi,0
syscall
退出程序,返回给操作系统0。
此文章为3月Day 7学习笔记,内容来源于极客时间《操作系统实战 45 讲》。
下一篇:【Python安装配置教程】