Intel® 64 and IA-32 Architectures Software Developer’s Manual 文档官方地址:
https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf
很好的入门文档:https://www.cdsy.xyz/computer/programme/masm/241210/cd64993.html
汇编语言由三部分组成:
具体可以参考:https://www.cdsy.xyz/computer/programme/masm/241211/cd65036.html
AT&T 和 INTEL 两种语法的主要差异有:
- | AT&T | INTEL |
---|---|---|
操作数方向 | 从左向右 | 从右向左 |
立即数表示方式 | $0x01 | 30h |
寄存器表示方式 | %eax | eax |
助记符指定操作数长度 | b8位,w16位,l32位, movl $lb, %eax | mov eax, dw ptr lb |
长跳转和调用 | ljmp $sect, $off | jmp sect:off |
内存单元 | 圆括号 mov 5(%ebx), %eax | 方括号 mov eax, [ebx + 5] |
间接寻址方式 | %segreg:disp(base,index,scale) | segreg:[base+index*scale+disp] |
注释 | 单行用 # 或 // 多行用 /* ... */ | 只有; |
AT&T 语法比较难受,但是 UNIX 类系统的源码都在用,所以还是要学习。
这两个平台,一个是 32 位,一个是 64 位,其系统调用编号完全不同。
NASM 编译器中,所有伪指令就是一般单词,没有用句点开头。
常用选项:
Unix 系列的操作系统基本默认用这个。伪指令全部用句点开头。可以直接通过 --32/--64/--x32 generate 32bit/64bit/x32 code 选项生成指定位数的代码。
源码:
section .text ; 声明代码段
global _start ; 声明程序入口
_start:
mov eax, 4 ; 参数一:系统调用号,4表示写
mov ebx, 1 ; 参数二:写的目的地,1表示 stdout
mov ecx, msg ; 参数三:要写的字符串首地址
mov edx, len ; 参数四:字符串长度
int 80h ; 开始系统调用
mov eax, 1
mov ebx, 0
int 80h
section .data ; 声明数据段
msg db "hello world!", 0xA
len equ $ - msg
编译链接执行,链接器 LD 用 -m elf_i386 指明链接的是 32 位的目标文件:
nasm hello.asm -o hello.o -f elf
ld hello.o -o hello -m elf_i386
./hello
.data # 数据段声明
msg : .string "Hello, world!\\n" # 要输出的字符串
len = . - msg # 字串长度
.text # 代码段声明
.global _start # 指定入口函数
_start: # 在屏幕上显示一个字符串
movl $len, %edx # 参数三:字符串长度
movl $msg, %ecx # 参数二:要显示的字符串
movl $1, %ebx # 参数一:文件描述符(stdout)
movl $4, %eax # 系统调用号(sys_write)
int $0x80 # 调用内核功能
# 退出程序
movl $0,%ebx # 参数一:退出代码
movl $1,%eax # 系统调用号(sys_exit)
int $0x80 # 调用内核功能
编译执行:
kika@kika-VirtualBox:~/test/gas$ as att.s -o att.o
kika@kika-VirtualBox:~/test/gas$ ld att.o -o att
kika@kika-VirtualBox:~/test/gas$ ./att
Hello, world!\n
这个太折腾了,建议不用