AT&T和Intel汇编杂谈

作者:小安
博客地址:我的博客

今天,我们来梳理一下这常见的x86/x64平台下汇编语言的格式。

前言

一个高级语言写的程序会编译为二进制文件,但是其中有一个步骤是反汇编,这也是人们所能可以理解最底层的语言了,继而汇编会被变成一堆二进制数据。
人们发明汇编的原因就是因为指令集非常不便于理解和阅读,但是说到指令集,人们有发明了两种指令集:复杂指令集和精简指令集,两者代表分别是如今PC端的霸主X86架构与移动端的霸主ARM架构处理器。
是不是有点晕乎了呢?是的,那请你看下方的流程发展图:

指令集架构ISA
复杂指令集CICS
Intelx86和AMD64
注: Linux发行版中
x86称i386,x86-64称amd64
x86/x64汇编
ATT风格和Intel风格
精简指令集RISC
1985年Acorn推出ARMv1
2011年ARMv8扩展到64bits
继承ARMv7称Arch32
注: Linux发行版中
AArch64称aarch64,AArch32称arm
ARM汇编

学一个东西就是这样,像极了“不识庐山真面目,只缘身在此山中”,从知识的海洋跳出来,站在山顶也许会有破局的妙计!

对比

AT&T和Intel汇编杂谈_第1张图片
这样看表已经明了很多了,网上好多人长篇大论都说不清,下面我们每个举个例子就明白了。

  1. 寄存器和操作数

前缀不同:在Intel的语法中,寄存器和和立即数都没有前缀。但是在AT&T中,寄存器前需要加上“%”,而立即数前需要加上“$”。

Intel语法 AT&T语法
mov eax,8 movl $8,%eax
  1. 十六进制

前缀不同: 在Intel的语法中,十六进制和二进制立即数后缀分别是“h”和“b”,而在AT&T中,十六进制立即数前需要加上“0x”。

Intel语法 AT&T语法
int 80h int $0x80
  1. 目标和源操作数

操作数方向不同:Intel与AT&T操作数的方向正好相反。在Intel语法中,第一个操作数是目的操作数,第二个操作数源操作数。而在AT&T中,第一个数是源操作数,第二个数是目的操作数。

Intel语法 AT&T语法
mov eax,[ecx] movl (%ecx),%eax
  1. 间接寻址表示

内存单元操作数不同:在Intel的语法中,基寄存器用“[]”括起来,而在AT&T中,用“()”括起来。

Intel语法 AT&T语法
mov eax,[ebx+5] movl 5(%ebx),%eax
  1. 操作位数后缀

后缀不同:在AT&T的操作码后面有一个后缀,其含义就是指出操作码的大小。"l"表示长整数(32位),"w"表示字(16位),"b"表示字节(8位)。而在Intel的语法中,则要在内存单元操作数的前面加上byte ptr, word ptr 和 dword ptr。

Intel语法 AT&T语法
mov al,bl movb %bl,%al
mov ax,bx movw %bx,%ax
mov eax,ebx movl %ebx,%eax
mov eax, dword ptr [ebx] movl (%ebx),%eax
  1. 间接寻址格式

寻址方式不同:Intel的指令格式是segreg:[base+index*scale+disp],而AT&T的格式是%segreg:disp(base,index,scale)。其中index/scale/disp/segreg全部是可选的,完全可以简化掉。如果没有指定scale而指定了index,则scale的缺省值为1。当立即数用在scale/disp中时,不应当在其前冠以“$”前缀。

Intel语法 AT&T语法
mov eax,[ebx+20h] movl 0x20(%ebx),%eax
add eax,[ebx+ecx*2h addl (%ebx,%ecx,0x2),%eax
lea eax,[ebx+ecx] leal (%ebx,%ecx),%eax
sub eax,[ebx+ecx*4h-20h] subl -0x20(%ebx,%ecx,0x4),%eax

破局

我们实战一下,用两种不同的汇编风格写一下HelloWorld。

  • AT&T格式
#hello.s 
.data                    # 数据段声明
        msg : .string "Hello, world!\\n" # 要输出的字符串
        len = . - msg                   # 字串长度
.text                    # 代码段声明
.global _start           # 指定入口函数

_start:                  # 在屏幕上显示一个字符串
        movl $len, %edx  # 参数三:字符串长度
        movl $msg, %ecx  # 参数二:要显示的字符串
        movl $1, %ebx    # 参数一:文件描述符(stdout) 
        movl $4, %eax    # 系统调用号(sys_write) 
        int  $0x80       # 调用内核功能

                         # 退出程序
        movl $0,%ebx     # 参数一:退出代码
        movl $1,%eax     # 系统调用号(sys_exit) 
        int  $0x80       # 调用内核功能
  • Intel格式
; hello.asm 
section .data            ; 数据段声明
        msg db "Hello, world!", 0xA     ; 要输出的字符串
        len equ $ - msg                 ; 字串长度
section .text            ; 代码段声明
global _start            ; 指定入口函数
_start:                  ; 在屏幕上显示一个字符串
        mov edx, len     ; 参数三:字符串长度
        mov ecx, msg     ; 参数二:要显示的字符串
        mov ebx, 1       ; 参数一:文件描述符(stdout) 
        mov eax, 4       ; 系统调用号(sys_write) 
        int 0x80         ; 调用内核功能
                         ; 退出程序
        mov ebx, 0       ; 参数一:退出代码
        mov eax, 1       ; 系统调用号(sys_exit) 
        int 0x80         ; 调用内核功能

应用

说了这么多,那这两种格式都在哪里应用呢??

  • IDA与OD应用Intel

AT&T和Intel汇编杂谈_第2张图片

AT&T和Intel汇编杂谈_第3张图片

  • Linux下gdb和gcc应用AT&T

AT&T和Intel汇编杂谈_第4张图片

AT&T和Intel汇编杂谈_第5张图片

总结

因为AT&T风格有更好的可移植性,所以在Linux的平台下有很好的支持,根据不同情况选择不同的风格进行工作学习,这也是人类的智慧。

参考AT&T汇编语言 和汇编语言编写的Hello World

你可能感兴趣的:(逆向,网络安全)