Linux内核中硬件相关的代码基本都是用AT&T汇编语言实现,最近决定系统学习一下,以下使用AT&T汇编语言编写的几个简单程序:
1. Hello World.
-
.section .rodata
-
hello:
-
.asciz "Hello, world" # 定义打印字符串,存放在数据段中,ro表示只读;
-
-
format:
-
.asciz "%s\n" # 定义打印格式字符串,存放在数据段中;
-
-
-
.section .text # 代码段定义main函数。
-
.globl main
-
main:
-
pushl $hello # push第二个参数到栈中
-
pushl $format # push第一个参数到栈中
-
call printf # 调用printf("%s\n", &hello)
-
addl $8, %esp
-
-
pushl $0
-
call exit # 调用exit(0)
编译运行的结果:
# gcc -o hello hello.s
./hello
Hello, world
2. 简单的加减法:
-
.section .rodata
-
a:
-
.int 100
-
b:
-
.int 200
-
-
.section .data
-
c:
-
.int 0
-
format:
-
.asciz "%d\n"
-
-
.section .text
-
.globl main
-
main:
-
movl b, %eax
-
addl a, %eax
-
movl %eax, c # c = a + b = 300
-
pushl c
-
pushl $format
-
call printf # printf("%d", c)
-
addl $8, %esp
-
-
movl b, %eax
-
subl a, %eax
-
movl %eax, c # c = a - b = 100
-
pushl c
-
pushl $format
-
call printf # printf("%d", c)
-
addl $8, %esp
-
-
pushl $0
-
call exit
编译运行结果:
# gcc -o math math.s
# ./math
300
100
3. if/else 判断
-
# judge.s
-
-
.section .rodata
-
num:
-
.int 1
-
-
iszero:
-
.asciz "num is 0\n"
-
-
notzero:
-
.asciz "num is not zero\n"
-
-
.section .text
-
.globl main
-
main:
-
cmp $0, num
-
jz Yes
-
No:
-
pushl $notzero
-
call printf
-
addl $4, %esp
-
-
jmp end
-
Yes:
-
pushl $iszero
-
call printf
-
addl $4, %esp
-
-
end:
-
pushl $0
-
call exit
编译运行:
# gcc -o judge judge.s
# ./judge
num is not zero
4. while循环打印0~100
-
# while.s
-
-
.section .data
-
format:
-
.asciz "%d\n"
-
-
num:
-
.int 0
-
-
.section .text
-
.globl main
-
main:
-
movl $0, num
-
loop:
-
movl num, %eax
-
addl $1, %eax
-
movl %eax, num
-
-
pushl %eax
-
pushl $format
-
call printf
-
addl $8, %esp
-
-
cmp $100, num
-
jnz loop
-
-
pushl $0
-
call exit
编译并运行:
# gcc -o while while.s
# ./while
0
1
2
...
100
5. 数组的访问
for循环打印数组中的元素
-
# array.s
-
-
.section .rodata
-
array:
-
.int 1, 2, 3 # 定义数组
-
format:
-
.asciz "%d\n"
-
-
.section .text
-
.globl main
-
main:
-
movl $array, %edi # 保存array的地址
-
for:
-
pushl (%edi) # 间接寻址得到array中的元素
-
pushl $format
-
call printf
-
addl $8, %esp
-
addl $4, %edi # 得到array中下一个元素的地址
-
cmp $format, %edi
-
jnz for
-
-
pushl $0
-
call exit
编译运行结果:
# gcc -o array array.s
# ./array
1
2
3
6. 基本的位操作
-
.section .data
-
num:
-
.int 1
-
-
format:
-
.asciz "num is %d\n"
-
-
zfstr:
-
.asciz "ZF is set\n"
-
-
.section .text
-
.globl main
-
main:
-
# 1. 算术左移
-
# a. 右边直接补0
-
# b. 左边移除的位放在CF进位标志中
-
sall num # num = 2
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 2. 逻辑左移
-
# a. 右边直接补0
-
# b. 左边移除的位放在CF进位标志中
-
shll num # num = 4
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 3. 算术右移动
-
# a. 左边补充符号位
-
# b. 右边移除的位放在CF进位标志中
-
sarl num # num = 2
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 4. 逻辑右移动
-
# a. 左边补充符号位
-
# b. 右边移除的位放在CF进位标志中
-
shrl num # num = 1
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 5. 与
-
andl $1, num # num = 1
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 6. 或
-
orl $2, num # num = 3
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 7. 循环右位移
-
rorl num # num = 10000000 | 00000000 | 00000000 | 00000001
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 8. 循环左位移
-
roll num # num = 3
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 9. 按位异或
-
xorl $1, num # num = 2
-
pushl num
-
push $format
-
call printf
-
addl $8, %esp
-
-
# 10. test并设置ZF
-
movl $1, %eax
-
test %eax, num
-
jz setzf
-
-
pushl $0
-
call exit
-
-
setzf:
-
pushl $zfstr
-
call printf
-
pushl $0
-
call exit
编译并运行:
# gcc -o bitop bitop.s
# ./bitop
num is 2
num is 4
num is 2
num is 1
num is 1
num is 3
num is -2147483647
num is 3
num is 2
ZF is set
7. 函数调用实现fibonacci数列
-
# finn.s
-
-
.section .rodata
-
format:
-
.asciz "finn(%d) = %d\n"
-
-
.section .text
-
.globl finn
-
.type @function
-
finn:
-
pushl %ebp # (1). 保存原始的ebp
-
movl %esp, %ebp # (2). 保存当前的esp
-
-
pushl %ebx # (3). 保存要被修改的寄存器
-
pushl %ecx
-
-
# 当前的栈的状态:
-
# +----------------+
-
# | ... |
-
# +----------------+
-
# | ... | <-- 12(%ebp)
-
# +----------------+
-
# | arg1 | <-- 8(%ebp)
-
# +----------------+
-
# | return address | <-- 4(%ebp)
-
# +----------------+
-
# | old ebp | <-- ebp
-
# +----------------+
-
# ^ | old ebx |
-
# | +----------------+
-
# memory | old ecx | <-- esp
-
# addresses +----------------+
-
-
movl 8(%ebp), %ebx # (4). 得到参数
-
cmpl $2, %ebx # (5). 参数与2比较
-
jle L1 # 参数 <= 2 则直接返回1, 否则计算finn(n-1) + finn(n-2)
-
-
subl $1, %ebx # (6). 得到(n-1)
-
pushl %ebx
-
call finn
-
addl $4, %esp
-
-
movl %eax, %ecx # (7). 得到finn(n-1)
-
-
subl $1, %ebx # (8). 得到(n-2)
-
pushl %ebx
-
call finn
-
addl $4, %esp
-
-
addl %ecx, %eax # (9). 得到finn(n-1) + finn(n-2)
-
jmp RET
-
-
L1:
-
movl $1, %eax
-
RET:
-
popl %ecx
-
popl %ebx
-
movl %ebp, %esp # (10). 得到(2)保存的esp
-
popl %ebp # (11). 得到(1)保存的ebp
-
ret
-
-
.globl main
-
main:
-
movl $10, %edi
-
pushl %edi # 将参数放到栈中
-
call finn
-
addl $4, %esp
-
-
pushl %eax
-
pushl %edi
-
pushl $format
-
call printf
-
addl $8, %esp
-
-
pushl $0
-
call exit
编译运行结果:
# gcc -o finn finn.s
# ./finn
finn(10) = 55
阅读(6041) | 评论(0) | 转发(3) |