section .data
msg db "hello,world",0xA
len equ $-msg
section .text
global _start
_start:
mov eax,4
mov ebx,1
mov ecx,msg
mov edx,len
int 0x80;触发系统调用
mov eax,1
xor ebx,ebx
int 0x80
一、快速运行
先从一段hello world的程序开始。
上述代码可以在linux ubuntu 22.04环境下运行。也可以采用跟C语言开发一样的makefile工具,makefile文件内容如下所示。
test:test.o
ld test.o -o test
test.o:test.asm
nasm -f elf64 test.asm
linux Ubuntu环境中需要事先安装好nasm和binutils相关工具。如果不清楚请执行下列命令。
sudo apt install nasm binutils
二、细节讲述
两个section,一个data一个text。text存储要执行的指令,data存储执行指令所需要的数据,由于汇编属于非常底层的语言,字符串的定义需要编程人员自己来判定字符串的长度。
len equ $-msg 含义就是len的长度为12。
但是将字符串打印到屏幕上时,应使用通过系统调用的方式,触发系统调用就采用int 0x80。但是使用时需要注意数据格式的填充,eax表示系统调用号,ebx表示输入到什么地方,1代表标准输出设备即屏幕,ecx表示待输出的字符串,采用ascii的方式进行存储,edx表示待打印出来的字节数量。
但是如果将len的数字打印到屏幕时还是比较复杂的,需要完成数字每一位的转换。这里采用转换的方式,len=12,当len+85时就得到97,也就是字符a的ascii值。所以采用下面代码。
section .data
msg db "hello,world",0xA
len equ $-msg
section .bss
outputBuffer resb 4;预申请4个字节,后续使用时注意数据写入的宽度
section .text
global _start
_start:
mov eax,4
mov ebx,1
mov ecx,msg
mov edx,len
int 0x80;触发系统调用
; Print Number 1
mov cl, 86
add cl, len
mov [outputBuffer], cl
mov [outputBuffer+1], cl
mov [outputBuffer+2], cl
mov cl, 0xA
mov [outputBuffer+3], cl
mov ecx,outputBuffer
mov eax,4
mov ebx,1
mov edx,4
int 0x80
mov eax,1
xor ebx,ebx
int 0x80
三、Intel汇编语法和AT&T汇编语法
Intel汇编语法和AT&T汇编语法二者在变量、常量、寄存器访问、间接寻址和偏移量等方面都存在巨大的差异。
AT&T汇编语法%作为所有寄存器名称的前缀,以$作为文字常量(也叫做立即操作数)的前缀。
.data
msg:
.ascii "hello,world"
len=.-msg
.text
.global _start
_start:
movl $4, %eax
movl $1, %ebx
movl $msg,%ecx
movl $len,%edx
int $0x80
movl $1,%eax
movl $0,%ebx
;xorl %ebx,%ebx
int $0x80
上述代码可以在linux ubuntu 22.04环境下运行。也可以采用跟C语言开发一样的makefile工具,makefile文件内容如下所示。
test:test.o
ld test.o -o test
test.o:test.asm
as -o test.o test.asm