AT&T汇编语言基础学习示例

来源:互联网 发布:软件系统测试方法 编辑:程序博客网 时间:2024/06/10 03:43
Linux内核中硬件相关的代码基本都是用AT&T汇编语言实现,最近决定系统学习一下,以下使用AT&T汇编语言编写的几个简单程序:

1. Hello World.

点击(此处)折叠或打开

  1. .section .rodata
  2. hello:
  3.   .asciz "Hello, world"        # 定义打印字符串,存放在数据段中,ro表示只读;

  4. format:
  5.   .asciz "%s\n"                # 定义打印格式字符串,存放在数据段中;


  6. .section .text                 # 代码段定义main函数。
  7. .globl main
  8. main:
  9.   pushl $hello                 # push第二个参数到栈中
  10.   pushl $format                # push第一个参数到栈中
  11.   call printf                  # 调用printf("%s\n", &hello)
  12.   addl $8, %esp

  13.   pushl $0
  14.   call exit                    # 调用exit(0)
编译运行的结果:
# gcc -o hello hello.s
./hello
Hello, world

2. 简单的加减法:

点击(此处)折叠或打开

  1. .section .rodata
  2. a:
  3.   .int 100
  4. b:
  5.   .int 200

  6. .section .data
  7. c:
  8.   .int 0
  9. format:
  10.   .asciz "%d\n"

  11. .section .text
  12. .globl main
  13. main:
  14.   movl b, %eax
  15.   addl a, %eax
  16.   movl %eax, c                        # c= a+ b = 300
  17.   pushl c
  18.   pushl $format
  19.   call printf                         # printf("%d", c)
  20.   addl $8, %esp

  21.   movl b, %eax
  22.   subl a, %eax
  23.   movl %eax, c                        # c= a- b = 100
  24.   pushl c
  25.   pushl $format
  26.   call printf                         # printf("%d", c)
  27.   addl $8, %esp

  28.   pushl $0
  29.   call exit
编译运行结果:
# gcc -o math math.s
# ./math
300
100

3. if/else 判断

 

  1. # judge.s

  2. .section .rodata
  3. num:
  4.   .int 1

  5. iszero:
  6.   .asciz "num is 0\n"

  7. notzero:
  8.   .asciz "num is not zero\n"

  9. .section .text
  10. .globl main
  11. main:
  12.   cmp $0, num
  13.   jz Yes
  14. No:
  15.   pushl $notzero
  16.   call printf
  17.   addl $4, %esp

  18.   jmp end
  19. Yes:
  20.   pushl $iszero
  21.   call printf
  22.   addl $4, %esp

  23. end:
  24.   pushl $0
  25.   call exit

编译运行:
# gcc -o judge judge.s
# ./judge
num is not zero

4. while循环打印0~100

点击(此处)折叠或打开

  1. # while.s
  2. .section .data
  3. format:
  4.   .asciz "%d\n"

  5. num:
  6.   .int 0

  7. .section .text
  8. .globl main
  9. main:
  10.   movl $0, num
  11. loop:
  12.   movl num, %eax
  13.   addl $1, %eax
  14.   movl %eax, num

  15.   pushl %eax
  16.   pushl $format
  17.   call printf
  18.   addl $8, %esp

  19.   cmp $100, num
  20.   jnz loop

  21.   pushl $0
  22.   call exit

编译并运行:
# gcc -o while while.s
# ./while
0
1
2
...
100

5. 数组的访问
for循环打印数组中的元素

点击(此处)折叠或打开

  1. # array.s

  2. .section .rodata
  3. array:
  4.    .int 1, 2, 3 # 定义数组
  5. format:
  6.    .asciz "%d\n"

  7. .section .text
  8. .globl main
  9. main:
  10.    movl $array, %edi # 保存array的地址
  11. for:
  12.    pushl (%edi) # 间接寻址得到array中的元素
  13.    pushl $format
  14.    call printf
  15.    addl $8, %esp
  16.    addl $4, %edi # 得到array中下一个元素的地址
  17.    cmp $format, %edi
  18.    jnz for

  19.    pushl $0
  20.    call exit
编译运行结果:
# gcc -o array array.s
# ./array
1
2
3
6. 基本的位操作

点击(此处)折叠或打开

  1. .section .data
  2. num:
  3.   .int 1

  4. format:
  5.   .asciz "num is %d\n"

  6. zfstr:
  7.   .asciz "ZF is set\n"

  8. .section .text
  9. .globl main
  10. main:
  11.   # 1. 算术左移
  12.   # a. 右边直接补0
  13.   # b. 左边移除的位放在CF进位标志中
  14.   sall num # num = 2
  15.   pushl num
  16.   push $format
  17.   call printf
  18.   addl $8, %esp

  19.   # 2. 逻辑左移
  20.   # a. 右边直接补0
  21.   # b. 左边移除的位放在CF进位标志中
  22.   shll num # num = 4
  23.   pushl num
  24.   push $format
  25.   call printf
  26.   addl $8, %esp

  27.   # 3. 算术右移动
  28.   # a. 左边补充符号位
  29.   # b. 右边移除的位放在CF进位标志中
  30.   sarl num # num = 2
  31.   pushl num
  32.   push $format
  33.   call printf
  34.   addl $8, %esp

  35.   # 4. 逻辑右移动
  36.   # a. 左边补充符号位
  37.   # b. 右边移除的位放在CF进位标志中
  38.   shrl num # num = 1
  39.   pushl num
  40.   push $format
  41.   call printf
  42.   addl $8, %esp

  43.   # 5.
  44.   andl $1, num # num = 1
  45.   pushl num
  46.   push $format
  47.   call printf
  48.   addl $8, %esp

  49.   # 6.
  50.   orl $2, num # num = 3
  51.   pushl num
  52.   push $format
  53.   call printf
  54.   addl $8, %esp

  55.   # 7. 循环右位移
  56.   rorl num # num = 10000000 | 00000000 | 00000000 | 00000001
  57.   pushl num
  58.   push $format
  59.   call printf
  60.   addl $8, %esp

  61.   # 8. 循环左位移
  62.   roll num # num = 3
  63.   pushl num
  64.   push $format
  65.   call printf
  66.   addl $8, %esp

  67.   # 9. 按位异或
  68.   xorl $1, num # num = 2
  69.   pushl num
  70.   push $format
  71.   call printf
  72.   addl $8, %esp

  73.   # 10. test并设置ZF
  74.   movl $1, %eax
  75.   test %eax, num
  76.   jz setzf

  77.   pushl $0
  78.   call exit

  79. setzf:
  80.   pushl $zfstr
  81.   call printf
  82.   pushl $0
  83.   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数列

点击(此处)折叠或打开

  1. # finn.s

  2. .section .rodata
  3. format:
  4.   .asciz "finn(%d) = %d\n"

  5. .section .text
  6. .globl finn
  7.   .type @function
  8. finn:
  9.   pushl %ebp                      # (1). 保存原始的ebp
  10.   movl %esp, %ebp                 #(2). 保存当前的esp

  11.   pushl %ebx                      # (3). 保存要被修改的寄存器
  12.   pushl %ecx

  13.   # 当前的栈的状态:
  14.   #              +----------------+
  15.   #              |      ...      |
  16.   #              +----------------+
  17.   #              |      ...      |<-- 12(%ebp)
  18.   #              +----------------+
  19.   #              |      arg1      | <-- 8(%ebp)
  20.   #              +----------------+
  21.   #              | return address | <-- 4(%ebp)
  22.   #              +----------------+
  23.   #              |     old ebp    | <--ebp
  24.   #              +----------------+
  25.   #     ^        |     old ebx    |
  26.   #     |        +----------------+
  27.   #   memory     |     old ecx    | <-- esp
  28.   #  addresses   +----------------+

  29.   movl 8(%ebp), %ebx              #(4). 得到参数
  30.   cmpl $2, %ebx                   #(5). 参数与2比较
  31.   jle L1                          # 参数 <= 2 则直接返回1, 否则计算finn(n-1)+ finn(n-2)

  32.   subl $1, %ebx                  #(6). 得到(n-1)
  33.   pushl %ebx
  34.   call finn
  35.   addl $4, %esp

  36.   movl %eax, %ecx                 #(7). 得到finn(n-1)

  37.   subl $1, %ebx                   #(8). 得到(n-2)
  38.   pushl %ebx
  39.   call finn
  40.   addl $4, %esp

  41.   addl %ecx, %eax                 #(9). 得到finn(n-1)+ finn(n-2)
  42.   jmp RET

  43. L1:
  44.   movl $1, %eax
  45. RET:
  46.   popl %ecx
  47.   popl %ebx
  48.   movl %ebp, %esp                # (10). 得到(2)保存的esp
  49.   popl %ebp                      # (11). 得到(1)保存的ebp
  50.   ret

  51. .globl main
  52. main:
  53.   movl $10, %edi
  54.   pushl %edi # 将参数放到栈中
  55.   call finn
  56.   addl $4, %esp

  57.   pushl %eax
  58.   pushl %edi
  59.   pushl $format
  60.   call printf
  61.   addl $8, %esp

  62.   pushl $0
  63.   call exit
编译运行结果:
# gcc -o finn finn.s
# ./finn
finn(10) = 55
原创粉丝点击