您的位置:首页 > 其它

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: