ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 概述 **常见的指令集以及汇编语言规范:** * x86(IA-32)、x86-64指令集(常见于PC端),对应有2家公司发布的不同汇编语言规范: * intel公司发布的汇编语言规范,称`intel 汇编`:Windows派系(Microsoft),比较著名的汇编器有微软的masm和开源的nasm。 * AT&T公司发布的汇编语言规范,称`AT&T 汇编`:Unix派系(或者说GNU),比如g++编译器等。 * ARM指令集(常见于嵌入式、移动端设备,粗略统计覆盖95%左右的手段):ARM公司发布的汇编语言规范,称`ARM 汇编(目前常见的是ARM 64汇编)`,见[官网文档](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.arm.com%2Farchitectures) ## 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 + index*scale + disp] | 寻址方式的区别,无论形式如何,都是实现如下的地址计算:(其中base和index必须是寄存器,disp和scale可以是常数)disp + base + index * scale | |--- |--- |--- | |movl -4(%ebp), %eax |mov eax, [ebp - 4]| 内存操作数的例子| | movl array(, %eax, 4), %eax| mov eax, [eax*4 + array]| 内存操作数的例子 | | movw array(%ebx, %eax, 4), %cx| mov cx, [ebx + 4*eax + array]| 内存操作数的例子| | movb $4, %fs:(%eax)| mov fs:eax, 4 | 内存操作数的例子| ## 搭建Intel的环境 * ubuntu16.04 或 ubuntu18.04 * vscode * dosbox * 文件后缀:.asm 安装dosbox ```shell 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 ```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