欢迎光临
我们一直在努力

计算机组组成原理 | AT&T格式 和 Intel格式

🤯 同一个CPU,两套“黑话”:AT&T格式 vs Intel格式,傻傻分不清楚?

寄存器前面到底要不要加“%”?操作数到底谁左谁右?一文终结你的所有困惑!

如果你曾经试图读懂Linux内核里的汇编代码,或者无意间用GCC编译时加了-S选项生成了汇编文件,你可能会对着屏幕发出灵魂拷问:

“这写的都是啥???”

明明CPU都是x86架构,凭什么我上课学的mov ax, bx到了Linux底下就变成了movl %ebx, %eax?寄存器前面多了个“%”,操作数顺序还反了,读起来像在照镜子——这到底是谁发明的“阴间语法”?

今天这篇文章,就是来帮你终结这场混乱的。我们将彻底讲透AT&T格式和Intel格式这对“孪生冤家”的全部区别,让你以后无论在Windows下写汇编,还是在Linux下读内核源码,都能无缝切换、游刃有余。

🧬 第一节:为什么会有两套语法?一段不得不说的“恩怨情仇”

故事要从上世纪讲起。

图片

Intel公司是x86架构处理器的缔造者。1978年6月8日,大名鼎鼎的8086处理器诞生。为了让程序员不用对着二进制0101秃头,Intel顺手设计了一套汇编语言助记符——这就是Intel风格汇编的由来。Windows和DOS世界几乎被它统治。

而在另一边,AT&T公司的前身——贝尔实验室,是C语言和Unix系统的出生地。这里的牛人们追求的是跨平台——他们希望汇编语言的语法能在不同架构的CPU上尽量统一(注意是语法跨平台,不是指令跨平台)。于是他们抛开Intel的规范,自立门户搞了一套汇编语法,这就是AT&T风格汇编的起源。

当Unix被移植到i386处理器时,自然也就沿用了AT&T的汇编格式。Linux作为Unix家族的一员,同样继承了这一传统。

所以现状就是:

  • Windows阵营 → Intel格式(你上课学的那套)

  • Linux/Unix阵营 → AT&T格式(GCC默认生成的那套)

两种格式背后是两种不同的工具链生态,不存在谁对谁错,只是“方言”不同罢了。而考研408统考要求掌握的是Intel格式,但万一题目给的是AT&T格式呢?看懂它,就是你比别人多一分的底气。

📊 第二节:一张表终结所有混乱(核心干货)

废话不多说,直接上表。这张表就是你以后查这两种格式区别的终极词典。

对比维度

AT&T 格式

Intel 格式

操作数顺序 op 源, 目的

(源在左,目的在右)

op 目的, 源

(目的在左,源在右)

寄存器表示 %eax

(寄存器名前必须加“%”)

eax

(直接写寄存器名)

立即数表示 $985

(立即数前必须加“$”)

985

(直接写数字)

内存地址表示 (af996h)

(用小括号)

[af996h]

(用中括号)

数据长度标识

指令后缀:b(字节)、w(字)、l(双字)

byte ptr

、word ptr、dword ptr 前缀

简单偏移 -8(%ebx)

(偏移量在括号外)

[ebx – 8]

(偏移量在括号内)

复杂寻址 4(%ebx, %ecx, 32)

(偏移量(基址, 变址, 比例因子))

[ebx + ecx*32 + 4]

([基址 + 变址×比例因子 + 偏移量])

指令大小写

只能用小写字母

大小写不敏感

远跳转/远调用 ljump $section, $offset jmp far section:offset
绝对跳转/调用

操作数前加 *

不需要

💡 记忆口诀:AT&T = A lot of Trouble & Trouble(麻烦多多)——要加%、要加$、顺序还反着来。Intel = 你上课学的那套,怎么顺手怎么来。

🔍 第三节:逐条拆解,包教包会

1️⃣ 操作数顺序——最让人崩溃的区别

这是两种格式最核心、最反直觉的区别。

Intel格式:mov eax, ebx → 把ebx的值赋给eax(目的在左,源在右)

AT&T格式:movl %ebx, %eax → 同样是把ebx的值赋给eax(源在左,目的在右)

你看,同样一条指令,两种写法操作数位置完全相反。如果你用Intel的思维去读AT&T代码,会直接把赋值方向搞反——这是新手最常见的错误。

AT&T之所以采用“源, 目的”的顺序,是为了与之前的Unix汇编器保持兼容。而这个顺序的根源,甚至可以追溯到PDP-11处理器的指令编码方式。历史遗留问题,没办法。

快速记忆:AT&T是“从左到右”读(源→目的),Intel是“从右到左**读”(目的←源)。

2️⃣ 前缀符号——寄存器要“%”,立即数要“$”

AT&T格式像个仪式感很强的人:

  • 寄存器前面必须加 %:%eax、%ebx

  • 立即数前面必须加 $:$985、$0xffff

Intel格式则简单粗暴:

  • 寄存器直接写:eax、ebx

  • 立即数直接写:985、`0ffffh

举个例子,同样是“把985赋给eax寄存器”:

  • AT&T:movl $985, %eax

  • Intel:mov eax, 985

快速记忆:AT&T = “有$有%”,Intel = “啥也没有”。

3️⃣ 内存地址的括号——圆括号 vs 方括号

AT&T格式用圆括号 ( ) 表示内存地址:

  • movl (%eax), %ebx → 把eax指向的内存地址中的值赋给ebx

Intel格式用方括号 [ ] 表示内存地址:

  • mov ebx, [eax] → 同样的意思

快速记忆:AT&T = “圆润”,Intel = “方正”。

4️⃣ 数据长度——后缀 vs 前缀

AT&T格式在指令后面加一个字母表示数据长度:

  • b = byte(字节,8位)

  • w = word(字,16位)

  • l = long(双字,32位)

  • q = quad word(四字,64位)

例如:movb、movw、movl、movq

Intel格式则在内存操作数前面加前缀:

  • byte ptr、word ptr、dword ptr、qword ptr

例如:mov byte ptr [af996h], 5

快速记忆:AT&T是“后缀党”,Intel是“前缀党”。

5️⃣ 寻址方式——从简单到复杂的完全对照

这是最容易把人绕晕的部分,我们来逐层拆解。

(1)最简单:寄存器间接寻址

AT&T

Intel

movl (%ebx), %eax mov eax, [ebx]

就是把ebx当成指针,去读它指向的内存。

(2)带偏移量

AT&T

Intel

movl -8(%ebx), %eax mov eax, [ebx – 8]

ebx指向的地址再减8,然后读内存。

(3)带变址和比例因子(完整形态)

这是数组访问的底层实现。假设你要访问a[i],其中a的基址在ebx,i在ecx,每个元素占4字节:

AT&T

Intel

movl 6(%ebx, %ecx, 4), %eax mov eax, [ebx + ecx*4 + 6]

完整公式:

  • AT&T:disp(%base, %index, scale) → 地址 = disp + base + index × scale

  • Intel:[base + index × scale + disp]

注意:在AT&T中,当scale/disp出现在复杂寻址中时,不需要在它们前面加$前缀。

🧠 第四节:为什么考研要考这个?——因为真的会考!

408统考大纲在“程序的机器级代码表示”章节中,虽然没有明确指定必须用哪种格式,但历年统考真题主要考查的是Intel格式。

但是!如果你只认识Intel格式,万一题目给了一段AT&T格式的代码让你分析(比如结合Linux内核源码的题目),你就直接傻眼了。两种格式的互译能力,是你在考场上比别人多拿几分的关键。

此外,GCC默认生成的汇编代码是AT&T格式的。如果你在Linux下做实验、读源码、甚至做CTF逆向题,遇到AT&T格式是家常便饭。

📚 第五节:真题闯关!看看你能对几道

🎯 真题一(格式识别题):

以下是一段汇编代码:

movl $10, %eax
addl %ebx, %eax

请问这是哪种汇编格式?

A. Intel格式  B. AT&T格式  C. 两种都是  D. 两种都不是

【参考答案】 B

【解析】 寄存器前有%(%eax、%ebx),立即数前有$($10),指令用小写且有l后缀表示双字——这些都是AT&T格式的典型特征。如果是Intel格式,应该写成:

mov eax, 10
add eax, ebx

🎯 真题二(格式转换题):

将以下Intel格式的汇编指令转换为AT&T格式:

Intel格式:mov [ebx + ecx*4 + 8], eax

【参考答案】movl %eax, 8(%ebx, %ecx, 4)

【解析】 转换要点:

  • 操作数顺序反转:目的[ebx+ecx*4+8]移到右边,源eax移到左边并加%

  • 寄存器加%:%eax、%ebx、%ecx

  • 内存地址用圆括号:8(%ebx, %ecx, 4)

  • 指令加l后缀表示双字:movl

  • 🎯 真题三(AT&T代码阅读理解):

    已知以下AT&T格式的汇编代码片段:

    movl 8(%ebp), %eax
    movl 12(%ebp), %edx
    addl %edx, %eax

    请写出对应的C语言代码(假设%ebp指向当前函数的栈帧底部)。

    【参考答案】

    int a, b;
    a = *(int *)(ebp + 8);   // 第一个参数
    b = *(int *)(ebp + 12);  // 第二个参数
    return a + b;            // addl %edx, %eax,结果在%eax中

    更简洁地,这对应一个简单的加法函数:

    int add(int a, int b) {
        return a + b;
    }

    【解析】 在x86的函数调用约定中,ebp+8通常是第一个参数,ebp+12是第二个参数。movl 8(%ebp), %eax把第一个参数读入eax,movl 12(%ebp), %edx把第二个参数读入edx,addl %edx, %eax执行加法,结果留在eax中作为返回值。

    🎯 真题四(寻址方式计算题):

    AT&T格式指令:movl 0x10(%ebx, %ecx, 4), %eax

    已知:%ebx = 0x1000,%ecx = 0x5

    请问该指令访问的内存地址是多少?

    A. 0x1010  B. 0x1020  C. 0x1024  D. 0x1014

    【参考答案】 C

    【解析】 AT&T格式中disp(%base, %index, scale)的地址计算公式为:disp + base + index × scale。

    代入数值:0x10 + 0x1000 + 0x5 × 4 = 0x10 + 0x1000 + 0x14 = 0x1024

    所以答案是 C。

    赞(0)
    未经允许不得转载:171主机测评 » 计算机组组成原理 | AT&T格式 和 Intel格式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址