英文原版地址:NASM Assembly Language Tutorials - asmtutor.com
背景知识
汇编语言是基础的。程序员在硬件上拥有的唯一接口是内核本身。为了使用汇编构建有用的程序,我们需要使用内核提供的linux系统调用。这些系统调用是内置在操作系统中的库,提供例如从键盘读取和输出到屏幕的函数。
当你调用一个系统调用,内核将立即暂停你的程序的执行。它将联系必要的驱动需要在硬件上执行你请求的任务然后将控制权还给你的程序。
注:驱动被叫做驱动是因为内核真的用它们去驱动硬件
通过将想要执行的函数号(操作码)存入到EAX寄存器以及将想传给系统调用的参数填充到剩余的寄存器,我们可以在汇编中完成系统调用。一个软件被请求INT命令中断,内核接管然后使用我们的参数从库调用函数。
举个例子,请求一个中断,当EAX寄存器为1时,将调用sys_exit,当EAX寄存器为4时将调用sys_write代替。如果函数需要,EBX,ECX和EDX将作为参数传递。
写代码
首先,我们在 .data 段创建一个变量 'msg' ,在本例中指定它为我们想输出的字符串'Hello World!'。在我们的代码段,我们通过提供一个全局标记 _start 表示程序的入口点,告诉内核从哪开始执行。
我们将使用系统调用sys_write来输出我们的消息到控制台窗口。这个函数在linux系统调用表中的操作码被分配为4。这个函数也带有三个参数,在请求中断来执行任务之前,将它们有序的存入EDX,ECX和EBX三个寄存器中。
传递的参数如下:
-
EDX将被存入字符串的长度(比特数)
-
ECX将被存入我们在 .data 段创建的变量的地址
-
EBX将被存入饿哦们想写入的文件(在本例中为标准化输出STDOUT)
传递参数的数据类型和意义可以再函数的定义中找到。
使用下边的命令编译,链接然后执行这个程序 hello.asm
SECTION .data
msg db 'Hello World!', 0Ah ; 指定msg变量为你的消息字符串
SECTION .text
global _start
_start:
mov edx, 13 ; 要写入的字节数,字符数加0ah
mov ecx, msg ; 将消息的内存地址复制ECX寄存器
mov ebx, 1 ; 写到标准输出
mov eax, 4 ; 调用 SYS_WRITE (kernel opcode 4)
int 80h
编译命令
nasm -f elf hello.asm
链接命令
ld -m elf_i386 hello.o -o hello
执行命令
./hello
最后会报错 Segmentation fault ,也就是段错误