概述

常见的指令集以及汇编语言规范: x86(IA-32)、x86-64指令集(常见于PC端),对应有2家公司发布的不同汇编语言规范:

  • intel公司发布的汇编语言规范,称intel 汇编:Windows派系(Microsoft),比较著名的汇编器有微软的masm和开源的nasm。
  • AT&T公司发布的汇编语言规范,称AT&T 汇编:Unix派系(或者说GNU),比如g++编译器等。

AT&T格式 和 Intel格式的区别

表格如下:

|AT&T格式|Intel格式|说明 |—— |pushl %eax|push eax|在AT&T汇编格式中,寄存器名要加上’ %‘作为前缀;而在Intel汇编格式中,寄存器名不需要加前缀 |pushl $1|push 1|在AT&T汇编格式中,用’$‘前缀表示一个立即操作数;而在Intel汇编格式中,立即数的表示不用带任何前缀 |addl $1, %eax|add eax, 1|AT&T和Intel格式中的源操作数和目标操作数的位置正好相反。在Intel汇编格式中,目标操作数在源操作数的左边;而在AT&T汇编格式中,目标操作数在源操作数的右边。 |movb val, %al|mov al, byte ptr val|在AT&T汇编格式中,操作数的字长由操作符的最后一个字母决定,后缀’b’、‘w’、’l’分别表示操作数为字节(byte,8比特)、字(word,16比特)和长字(long,32比特);而在Intel汇编格式中,操作数的字长是用"byte ptr"和"word ptr"等前缀来表示的。 |ljump $section, $offset|jmp far section:offset|在AT&T汇编格式中,绝对转移和调用指令(jump/call)的操作数前要加上’‘作为前缀,而在Intel格式中则不需要。远程转移指令和远程子调用指令的操作码,在AT&T汇编格式中为"ljump"和"lcall",而在Intel汇编格式中则为"jmp far"和"call far" |lcall $section, $offset|call far section:offset|同上 |lret $stack_adjust|ret far stack_adjust|与之相应的远程返回指令 |section:disp(base, index, scale)|section:[base + indexscale + disp]|寻址方式的区别,无论形式如何,都是实现如下的地址计算:(其中base和index必须是寄存器,disp和scale可以是常数)disp + base + index * scale |—|—|— |movl -4(%ebp), %eax|mov eax, [ebp - 4]|内存操作数的例子 |movl array(, %eax, 4), %eax|mov eax, [eax4 + array]|内存操作数的例子 |movw array(%ebx, %eax, 4), %cx|mov cx, [ebx + 4eax + array]|内存操作数的例子 |movb $4, %fs:(%eax)|mov fs:eax, 4|内存操作数的例子

搭建Intel的环境

  • ubuntu16.04 或 ubuntu18.04- vscode- dosbox- 文件后缀:.asm 安装dosbox
sudo apt-get install dosbox

下载vscode插件MASM/TASM

Intel的hello.asm

;description
DATA SEGMENT USE16
    MYWORD DB "hello world!!!"
DATA ENDS

;description
CODE SEGMENT USE16
    ASSUME CS:CODE, DS:DATA ;代表谁是代码段,谁是数据段
main:
    mov AX, DATA ;数据首地址赋值给AX, ax是寄存器
    mov DS, AX   ;使得DS等价于AX,同样指向数据段
    LEA DX, MYWORD ;使DX寄存器指向数据变量word的首地址
    mov AH, 09h ;AH输出数据
    INT 21h ;执行AH的09h功能, 输出数据
    mov AX, 4c00h ;设置寄存器的功能
    INT 21h ;调用寄存器功能 程序结束
CODE ENDS

END main

在文件中点击鼠标右键运行程序

搭建AT&T的环境

  • ubuntu16.04 或 ubuntu18.04- vscode- 文件后缀: .s- gcc 下载vscode插件GNU Assembler Language Support

AT&T的hello.s

#hello.s
 
.data#数据段声明
 
msg : .string "Hello, world\n" #要输出的字符串
len = . - msg       #字串长度
 
.text               #代码段声明
.global main      #指定入口函数
 
main:             #在屏幕上显示一个字符串
    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            #调用内核功能

编译运行

$ gcc hello.s -o hello_att
$ ./hello_att

通过objdump查看到的几种cpu架构

$ objdump --help
objdump:支持的体系结构: i386 i386:x86-64 i386:x64-32 i8086 i386:intel i386:x86-64:intel i386:x64-32:intel i386:nacl i386:x86-64:nacl i386:x64-32:nacl iamcu iamcu:intel l1om l1om:intel k1om k1om:intel plugin

下列 i386/x86-64 特定的反汇编器选项在使用 -M 开关时可用(使用逗号分隔多个选项):
  x86-64      Disassemble in 64bit mode
  i386        Disassemble in 32bit mode
  i8086       在 16 位模式下反汇编
  att         用 AT&T 语法显示指令
  intel       用 Intel 语法显示指令
  att-mnemonic
              Display instruction in AT&T mnemonic
  intel-mnemonic
              Display instruction in Intel mnemonic
  addr64      假定 64 位地址大小
  addr32      假定 32 位地址大小
  addr16      假定 16 位地址大小
  data32      假定 32 位数据大小
  data16      假定 16 位数据大小
  suffix      在 AT&T 语法中始终显示指令后缀
  amd64       Display instruction in AMD64 ISA
  intel64     Display instruction in Intel64 ISA

汇编学习地址:http://c.biancheng.net/view/3463.html

--完--