AT&T汇编语言基础学习示例
2013-11-22 13:40
531 查看
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
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
相关文章推荐
- Linux内核学习系列---排队自旋锁
- 浅析淘宝网络通信库tbnet的实现
- 使用Tair时遇到pthread_join段错误问题解决
- 银行
- Asp.Net中使用Couchbase——Memcached缓存入门篇
- jquery easy ui 1.3.4 快速入门(1)
- 自动付款F110--DMEE
- OpenDiscussion_DataDrivenDesign
- .net jMail收邮件(含写入数据库及收取附件)
- 黑色星期五
- Brief Intro to Foundation Functions
- 甘特图与任务管理
- 今天的程序
- GitHub 教程 in Ubuntu
- 三星苹果还能笑多久?联想挑战智能手机全球霸主
- 德邦初级认证准备(三)
- 交流群里遇到的一个小问题
- platform_driver_register( )过程追踪
- 交流群里遇到的一个小问题
- 我的老东家联发科与高通的假话题与真危机