参考:
1. 阮一峰的网络日志:汇编语言入门教程
2. x86 Assembly Guide
3. Linux 汇编器:对比 GAS 和 NASM
目录:
1. 何为汇编?GAS和NASM汇编器对比
2. 基本的汇编语法与指令(基于AT&T语法)
3. 汇编中的系统调用
4. 几个汇编程序例子
assembly language --> 将文字指令(add,mov等)译成二进制机器码
.s
基于AT&T指令,采用GAS编译
.asm
基于intel指令,采用NASM编译
.o
链接文件,win下是obj文件
.a
静态链接,多个.o打包而成
.so
动态链接,多个.o打包而成
GAS汇编:基于AT&T指令,.s后缀
NASM汇编:基于intel指令,.asm后缀
GAS: GNU Assembler
NASM: Netwide Assembler
汇编格式对比:(linux64位下)
GAS编译 hello.s
as hello.s -o hello.o
NASM编译 hello.asm
nasm -f elf64 hello.asm -o hello.o
(elf64/elf32指定64/32位机器)
链接部分一致:
ld hello.o -o hello
(生成hello可执行文件)
UNIX上汇编基本基于AT&T语法,因此下面全部基于使用AT&T指令格式
x86的6个32位通用寄存器:
%eax
%ebx
%ecx
%edx
%edi
%esi
系统调用的sys_exit():
int $0x80
基本语法示例:
movl $1 %eax
表示将1存入eax寄存器
.data段
:已初始化的变量
.bss段
:未初始化的变量
.text段
:代码段
下面给出示例:
.data
msg:
.ascii "Hello, world!\n"
len = . - msg
.text
.global _start
_start:
movl $len,%edx
movl $msg,%ecx
movl $1,%ebx
movl $4,%eax
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
.byte
:1字节整型 0~255
.int
:2字节整型 0~65535
.long
:4字节整型 即C/C++的int
.ascii
:1字节char字符
下面给出示例:
data_list:
.long 12,34,98
data:
.int 3456677
strHello:
.ascii "luhao\0" # 实际长度是6,末尾'\0'是结束符
立即寻址:
mov $1, %eax
将数值1送入eax寄存器
直接寻址:
mov 0xff004, %eax
将物理(虚拟)地址0xff004上的值送入eax寄存器
间接寻址:
mov (%ebx), %eax
将ebx中存的地址中的值,送入eax
基址寻址:
mov 4(%ebx), %eax
将ebx中存的地址的后4字节处(+4),送入eax中
索引寻址:
mov Data_List(, %ecx, 4), %eax
注意Data_List存放4字节的long,因此每次后移4字节
假设%ecx存的是0,则取出的是Data_List中第一个元素,送入eax中
重点:.ascii数据格式
sys_write系统调用
// hello.s
.data
msg:
.ascii "Hello world!\n"
len = . - msg
.text
.global _start
_start:
movl $len,%edx # size of buffer
movl $msg,%ecx # content of buffer
movl $1,%ebx # fd 0:stdin 1:stdout
movl $4,%eax # sys_write
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
重点:.long数据格式
jmp指令
汇编实现循环loop
# max.s
# Code: find max element of the list
# GNU AS: based on AT&T
# %ebx: max
# %eax: tmp
# %edi: index
.data
data_items:
.long 1,2,3,4,5,0
.text
.globl _start
_start:
mov $0, %edi
mov data_items(, %edi, 4), %eax
mov %eax, %ebx
for_loop:
cmp $0, %eax
je exit_loop # if eax==0, exit
incl %edi
mov data_items(, %edi, 4), %eax
cmp %ebx, %eax
jle for_loop
mov %eax, %ebx
jmp for_loop
exit_loop:
mov $1, %eax
int $0x80
# why can echo $? stdout "5" in %ebx?
重点:.lcomm数据格式(未初始化)
算式/逻辑移位
# pocnt.s
# count '1' in uint64_t of Binary-Format
.bss
.lcomm buf,10
.data
str:
.ascii "test luhao!\n"
.text
.globl _start
_start:
mov $0x1111ffff1111ffff, %rax # number HEX
mov $0, %edx # count '1'
mov $64, %ecx # loop variable
# 16 for int32
# 32 for int64
_loop1:
ror $1, %rax # shift left 1
jnc _loop2 # if CF=0, jump to loop2
inc %edx # else: count '1' += 1
_loop2:
dec %ecx # ecx -= 1
jne _loop1 # if ecx!=0, go back to loop
add $0x30, %edx
mov $0, %rax
mov %edx,buf(,%rax,1)
mov $0xa, %edx
inc %rax
mov %edx,buf(,%rax,1)
mov $1, %ebx # fd: stdout
mov $4, %rax # sys_write
mov $buf, %ecx # buf
mov $2, %edx # size
int $0x80
#mov $0, %ebx
mov $1, %rax
int $0x80