简易学习汇编
这几种常用指令的作用要知道其含义
- push xxx == rsp <- rsp-8; [rsp] <- xxx
- pop xxx == xxx <- [rsp]; rsp <- rsp+8
- call xxx == push rip; rip <- xxx
- ret == pop rip
- leave == mov rsp, rbp; pop rbp
复制代码AT&T汇编一般有这样的格式。
- .section .data
- 初始化的数据
- .section .bss
- 未初始化的数据
- .section .rodata
- 只读数据
- .section .text
- .globl _start
- _start:
- 指令序列
复制代码通常可以使用
- as -o xxx.o xxx.s
- ld -o xxx xxx.o
复制代码来汇编和链接
把
- .section .text
- .globl _start
- _start:
复制代码改成
- .section .text
- .globl main
- main:
复制代码即可使用gcc(其实gcc只是一个driver)来编译
- gcc -o xxx xxx.s
复制代码如果你使用as和ld的话,可以使用别的标号来代替_start,只要在ld的-e参数指明入口点标号就行(当然你还可以修改.section信息,通过ld的参数或者脚本来控制)
,如果需要生成gdb可解析的符号表,使得程序可以用gdb调试,就使用
- as -gstabs -o xxx.o xxx.s
复制代码,如果使用了库函数则要用
- ld -dynamic-linker /lib/ld-linux-x86-64.so.2 xxx -lc xxx.o
复制代码来链接,或者直接使用
- gcc -o xxx xxx.s
复制代码,前提是你的汇编代码入口是main
一般人几乎不会直接使用汇编,所以编译器就成了汇编器的最大用户,这里我们来用反汇编的方法学习汇编的框架,至于指令的细节是一定要去查看Inte和AMD手册的。如果你不满足于算法对效率的提升还想在指令级手工优化代码,或者想让编译器生成更加优化的代码,Intel 64 and IA-32 Architectures Optimization Reference Manual是非常值得推荐的。
- #include <stdio.h>
- int main()
- {
- int a = 1;
- int b = 2;
- if(a > b)
- printf("a:%d is bigger\n", a);
- else
- printf("b:%d is bigger\n", b);
- return 0;
- }
复制代码然后用
- gcc -S a.c
复制代码编译代码,就会在当前目录下生成一个对应的汇编文件a.s
- .file "a.c"
- .section .rodata------两个字符串常量是只读的
- .LC0:
- .string "a:%d is bigger\n"
- .LC1:
- .string "b:%d is bigger\n"
- .text
- .globl main
- .type main, @function------主函数
- main:
- .LFB2:----------------------
- pushq %rbp---------------pushq,64位,所以是q。保存rbp,以便使用rbp作为栈指针
- .LCFI0:
- movq %rsp, %rbp-----------保存栈frame,现在有些编译器开发者致力于优化函数调用,优化这个frame就是其中一项
- .LCFI1:
- subq $16, %rsp------------调整rsp,为变量留下空间
- .LCFI2:---------------------
- movl $1, -4(%rbp)------把常量1(a)入栈,占4个字节。EMT64下int是4字节的
- movl $2, -8(%rbp)------把常量2(b)入栈,占4个字节
- movl -4(%rbp), %eax-----从栈中把1放到eax中去
- cmpl -8(%rbp), %eax-----比较栈中的2和eax中的1
- jle .L2-----------如果cmp操作的第2个操作数小于或等于cmp操作的第1个操作数就jmp到.L2,注意AT&T语法和Intel语法的不同,操作数的顺序是相反的
- movl -4(%rbp), %esi
- movl $.LC0, %edi
- movl $0, %eax
- call printf
- jmp .L4
- .L2:------------else部分---------gcc4的函数调用规范-----------
- movl -8(%rbp), %esi------从栈中取b的值放入esi
- movl $.LC1, %edi-------把字符串"b:%d is bigger\n"的地址放入edi
- movl $0, %eax---------把0放入eax
- call printf----------调用printf函数
- .L4:
- movl $0, %eax---------return 0;这一句的返回值0放在eax中
- leave---------------离开这个frame
- ret----------------返回
- .LFE2:
- .size main, .-main
- .section .eh_frame,"a",@progbits
- .Lframe1:
- .long .LECIE1-.LSCIE1
- .LSCIE1:
- .long 0x0
- .byte 0x1
- .string "zR"
- .uleb128 0x1
- .sleb128 -8
- .byte 0x10
- .uleb128 0x1
- .byte 0x3
- .byte 0xc
- .uleb128 0x7
- .uleb128 0x8
- .byte 0x90
- .uleb128 0x1
- .align 8
- .LECIE1:
- .LSFDE1:
- .long .LEFDE1-.LASFDE1
- .LASFDE1:
- .long .LASFDE1-.Lframe1
- .long .LFB2
- .long .LFE2-.LFB2
- .uleb128 0x0
- .byte 0x4
- .long .LCFI0-.LFB2
- .byte 0xe
- .uleb128 0x10
- .byte 0x86
- .uleb128 0x2
- .byte 0x4
- .long .LCFI1-.LCFI0
- .byte 0xd
- .uleb128 0x6
- .align 8
- .LEFDE1:
- .ident "GCC: (GNU) 4.2.3 (Ubuntu 4.2.3-2ubuntu7)"
- .section .note.GNU-stack,"",@progbits
复制代码如果if条件比较复杂比如
- if(condition1 || condition2)
复制代码或
- if(condition1 && condition2)
复制代码就分别使用
- cmpx x1, x2
- jxx xx
- cmpx x3, x4
- jxx xxx
复制代码和
- cmpx x1, x2
- jxx L
- .L:
- cmpx x3, x4
- jxx xxx
复制代码分别与之对应
- #include <stdio.h>
- int main()
- {
- int i;
- int j = 0;
- for(i = 0; i <= 3; i++){
- j += i;
- printf("j is %d\n", j);
- }
- return 0;
- }
复制代码有
- .file "a.c"
- .section .rodata
- .LC0:
- .string "j is %d\n"
- .text
- .globl main
- .type main, @function
- main:
- .LFB2:
- pushq %rbp
- .LCFI0:
- movq %rsp, %rbp
- .LCFI1:
- subq $16, %rsp
- .LCFI2:
- movl $0, -8(%rbp)------- i
- movl $0, -4(%rbp)------- j
- jmp .L2
- .L3:
- movl -4(%rbp), %eax------ i
- addl %eax, -8(%rbp)------ j += i
- movl -8(%rbp), %esi
- movl $.LC0, %edi
- movl $0, %eax
- call printf
- addl $1, -4(%rbp)------------- i++
- .L2:
- cmpl $3, -4(%rbp)-------------
- jle .L3----------------- i <=3
- movl $0, %eax------返回值
- leave
- ret
- .LFE2:
- .size main, .-main
- .section .eh_frame,"a",@progbits
复制代码
- #include <stdio.h>
- int main()
- {
- int i = 3;
- int j = 0;
- while(i >= 0){
- j += i;
- i--;
- printf("j is %d\n", j);
- }
- return 0;
- }
复制代码有
- .file "a.c"
- .section .rodata
- .LC0:
- .string "j is %d\n"
- .text
- .globl main
- .type main, @function
- main:
- .LFB2:
- pushq %rbp
- .LCFI0:
- movq %rsp, %rbp
- .LCFI1:
- subq $16, %rsp
- .LCFI2:
- movl $3, -4(%rbp)
- movl $0, -8(%rbp)
- jmp .L2
- .L3:
- movl -4(%rbp), %eax
- addl %eax, -8(%rbp)
- subl $1, -4(%rbp)--------------- i--
- movl -8(%rbp), %esi
- movl $.LC0, %edi
- movl $0, %eax
- call printf
- .L2:
- cmpl $0, -4(%rbp)---------------
- jns .L3-------------------- i >= 0
- movl $0, %eax
- leave
- ret
- .LFE2:
- .size main, .-main
- .section .eh_frame,"a",@progbits
复制代码
- #include <stdio.h>
- int main()
- {
- int i = 3;
- int j = 0;
- do{
- j += i;
- i--;
- printf("j is %d\n", j);
- }while(i >= 0);
- return 0;
- }
复制代码有
- .file "a.c"
- .section .rodata
- .LC0:
- .string "j is %d\n"
- .text
- .globl main
- .type main, @function
- main:
- .LFB2:
- pushq %rbp
- .LCFI0:
- movq %rsp, %rbp
- .LCFI1:
- subq $16, %rsp
- .LCFI2:
- movl $3, -4(%rbp)
- movl $0, -8(%rbp)
- .L2:
- movl -4(%rbp), %eax
- addl %eax, -8(%rbp)
- subl $1, -4(%rbp)
- movl -8(%rbp), %esi
- movl $.LC0, %edi
- movl $0, %eax
- call printf
- cmpl $0, -4(%rbp)-----------
- jns .L2---------------- while(i >= 0);
- movl $0, %eax
- leave
- ret
- .LFE2:
- .size main, .-main
- .section .eh_frame,"a",@progbits
复制代码
- #include <stdio.h>
- int a = 6;
- int b = 5;
- int add(int x, int y)
- {
- int z;
- z = x + y;
- return z;
- }
- int main()
- {
- int m;
- add(a, b);
- //printf("%d\n", add(a, b));
- return 0;
- }
复制代码生成的汇编是
- .file "a.c"
- .globl a-----------全局变量a
- .data-----------数据段
- .align 4----------4字节对齐
- .type a, @object-----a是一个对象
- .size a, 4--------大小4字节
- a:
- .long 6-----------a的值是6
- .globl b
- .align 4
- .type b, @object
- .size b, 4
- b:
- .long 5
- .text
- .globl add
- .type add, @function-------------全局函数add
- add:
- .LFB2:
- pushq %rbp
- .LCFI0:
- movq %rsp, %rbp
- .LCFI1:
- movl %edi, -20(%rbp)
- movl %esi, -24(%rbp)
- movl -24(%rbp), %eax
- addl -20(%rbp), %eax
- movl %eax, -4(%rbp)
- movl -4(%rbp), %eax------------eax保存返回值
- leave
- ret
- .LFE2:
- .size add, .-add
- .globl main
- .type main, @function
- main:
- .LFB3:
- pushq %rbp
- .LCFI2:
- movq %rsp, %rbp
- .LCFI3:
- subq $16, %rsp
- .LCFI4:
- movl b(%rip), %esi
- movl a(%rip), %edi
- call add
- movl $0, %eax
- leave
- ret
- .LFE3:
- .size main, .-main
- .section .eh_frame,"a",@progbits
复制代码还可以继续实验加入各种变量和函数还会见到.coom等标识,这样学习汇编不错。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
呵呵,不错。64位的
我的机器是intel core2的
good job...
收藏先,汇编也快忘了……
好贴
very clear
下面这些代码是什么意思哟
.long .LASFDE1-.Lframe1
.long .LFB2
.long .LFE2-.LFB2
.uleb128 0x0
.byte 0x4
.long .LCFI0-.LFB2
.byte 0xe
.uleb128 0x10
.byte 0x86
.uleb128 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.uleb128 0x6
.align 8
定了一堆内存
在这里可能是对一个C语言结构初始化的编译
没有人把这样的好帖做成精华帖啊。有点可惜啊。