(转) at&T语法格式 与 at&T - intel格式对比
movl (%ebp), %eax,
等同于Intel格式中的
mov EAX, [EBP + ]
,AT&T中,源操作数在左,目的操作数在右。“l”是Longword,相当于Intel格式中的dword ptr操作限定符;
表示将地址SS:[EBP +12]指向的双字数据传送至EAX寄存器。
addl (%ebp), %eax,
等同于Intel格式中的
add EAX, [EBP + ],
表示将SS:[EBP + 8]指向的一个双字数据同寄存器EAX中的原值相加,所得的结果保存在EAX寄存器。
ebp+xx是参数偏移,ebp-xx是局部变量偏移
参数 N <--- [ebp+4*N+4]
参数 2 <--- [ebp+12]
参数 1 <--- [ebp+8]
返回地址 <--- [ebp+4]
旧的ebp值(调用者的ebp) <--- [ebp]
局部变量 1 <---[ebp-4]
局部变量 2 <--- [ebp-8]
所以
- 在 AT&T 汇编格式中,寄存器名要加上 '%' 作为前缀;而在 Intel 汇编格式中,寄存器名不需要加前缀。例如:
|
AT&T 格式
|
Intel 格式
|
|
pushl %eax
|
push eax
|
- 在 AT&T 汇编格式中,用 '$' 前缀表示一个立即操作数;而在 Intel 汇编格式中,立即数的表示不用带任何前缀。例如:
|
AT&T 格式
|
Intel 格式
|
|
pushl $1
|
push 1
|
- AT&T 和 Intel 格式中的源操作数和目标操作数的位置正好相反。在 Intel 汇编格式中,目标操作数在源操作数的左边;而在 AT&T 汇编格式中,目标操作数在源操作数的右边。例如:
|
AT&T 格式
|
Intel 格式
|
|
addl $1, %eax
|
add eax, 1
|
- 在 AT&T 汇编格式中,操作数的字长由操作符的最后一个字母决定,后缀'b'、'w'、'l'分别表示操作数为字节(byte,8 比特)、字(word,16 比特)和长字(long,32比特);而在 Intel 汇编格式中,操作数的字长是用 "byte ptr" 和 "word ptr" 等前缀来表示的。例如:
|
AT&T 格式
|
Intel 格式
|
|
movb val, %al
|
mov al, byte ptr val
|
- 在 AT&T 汇编格式中,绝对转移和调用指令(jump/call)的操作数前要加上'*'作为前缀,而在 Intel 格式中则不需要。
- 远程转移指令和远程子调用指令的操作码,在 AT&T 汇编格式中为 "ljump" 和 "lcall",而在 Intel 汇编格式中则为 "jmp far" 和 "call far",即:
|
AT&T 格式
|
Intel 格式
|
|
ljump $section, $offset
|
jmp far section:offset
|
|
lcall $section, $offset
|
call far section:offset
|
- 与之相应的远程返回指令则为:
|
AT&T 格式
|
Intel 格式
|
|
lret $stack_adjust
|
ret far stack_adjust
|
- 在 AT&T 汇编格式中,内存操作数的寻址方式是
section:disp(base, index, scale)
- 而在 Intel 汇编格式中,内存操作数的寻址方式为:
section:[base + index*scale + disp]
- 由于 Linux 工作在保护模式下,用的是 32 位线性地址,所以在计算地址时不用考虑段基址和偏移量,而是采用如下的地址计算方法:
disp + base + index * scale
- 下面是一些内存操作数的例子:
|
AT&T 格式
|
Intel 格式
|
|
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
|
#hello.s
.data # 数据段声明
msg : .string "Hello, world!\\n" # 要输出的字符串
len = . - msg # 字串长度
.text # 代码段声明
.global _start # 指定入口函数
_start: # 在屏幕上显示一个字符串
movl $len, %edx # 参数三:字符串长度
movl $msg, %ecx # 参数二:要显示的字符串
movl $, %ebx # 参数一:文件描述符(stdout)
movl $, %eax # 系统调用号(sys_write)
int $0x80 # 调用内核功能
# 退出程序
movl $,%ebx # 参数一:退出代码
movl $,%eax # 系统调用号(sys_exit)
int $0x80 # 调用内核功能
; 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, ; 参数一:文件描述符(stdout)
mov eax, ; 系统调用号(sys_write)
int 0x80 ; 调用内核功能
; 退出程序
mov ebx, ; 参数一:退出代码
mov eax, ; 系统调用号(sys_exit)
int 0x80 ; 调用内核功能
平台下有两种方式来使用系统调用:利用封装后的
C
库(libc)或者通过汇编直接调用。其中通过汇编语言来直接调用系统调用,是最高效地使用
Linux
内核服务的方法,因为最终生成的程序不需要与任何库进行链接,而是直接和内核通信。
下的系统调用也是通过中断(int
0x80)来实现的。在执行 int 80 指令时,寄存器 eax
中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器
ebx,ecx,edx,esi,edi
中,当系统调用完成之后,返回值可以在寄存器 eax
中获得。
/usr/include/bits/syscall.h
中找到,为了便于使用,它们是用
SYS_<name>
这样的宏来定义的,如 SYS_write、SYS_exit
等。例如,经常用到的 write
函数是如下定义的:
ssize_t write(int fd, const void *buf, size_t count);
void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);c
# args.s
.text
.globl _start
_start:
popl %ecx # argc
vnext:
popl %ecx # argv
test %ecx, %ecx # 空指针表明结束
jz exit
movl %ecx, %ebx
xorl %edx, %edx
strlen:
movb (%ebx), %al
inc %edx
inc %ebx
test %al, %al
jnz strlen
movb $, -(%ebx)
movl $, %eax # 系统调用号(sys_write)
movl $, %ebx # 文件描述符(stdout)
int $0x80
jmp vnext
exit: movl $,%eax # 系统调用号(sys_exit)
xorl %ebx, %ebx # 退出代码
int $0x80
ret
C
语言程序中,从而充分利用高级语言和汇编语言各自的特点。但一般来讲,在
C
代码中嵌入汇编语句要比"纯粹"的汇编语言代码复杂得多,因为需要解决如何分配寄存器,以及如何与C代码中的变量相结合等问题。
提供了很好的内联汇编支持,最基本的格式是:
|
__asm__("asm statements");
|
|
__asm__("nop");
|
|
__asm__( "pushl %%eax \\n\\t"
"movl $0, %%eax \\n\\t"
"popl %eax");
|
代码中的汇编语句很难做到与其它部分没有任何关系,因此更多时候需要用到完整的内联汇编格式:
|
__asm__("asm statements" : outputs : inputs :
registers-modified); |
代码中的汇编语句是以":"分隔的四个部分,其中第一部分就是汇编代码本身,通常称为指令部,其格式和在汇编语言中使用的格式基本相同。指令部分是必须的,而其它部分则可以根据实际情况而省略。
内联汇编语句的指令部中,加上前缀''%''的数字(如%0,%1)表示的就是需要使用寄存器的"样板"操作数。指令部中使用了几个样板操作数,就表明有几个变量需要与寄存器相结合,这样GCC和GAS在编译和汇编时会根据后面给定的约束条件进行恰当的处理。由于样板操作数也使用''
%''作为前缀,因此在涉及到具体的寄存器时,寄存器名前面应该加上两个''%'',以免产生混淆。
int main()
{
int a = , b = ;
__asm__ __volatile__("movl %1, %%eax;\\n\\r"
"movl %%eax, %0;"
:"=r"(b)
:"r"(a)
:"%eax");
printf("Result: %d, %d\\n", a, b);
}
- 变量b是输出操作数,通过%0来引用,而变量a是输入操作数,通过%1来引用。
- 输入操作数和输出操作数都使用r进行约束,表示将变量a和变量b存储在寄存器中。输入约束和输出约束的不同点在于输出约束多一个约束修饰符''=''。
- 在内联汇编语句中使用寄存器eax时,寄存器名前应该加两个''%'',即%%eax。内联汇编中使用%0、%1等来标识变量,任何只带一个''%''的标识符都看成是操作数,而不是寄存器。
- 内联汇编语句的最后一个部分告诉GCC它将改变寄存器eax中的值,GCC在处理时不应使用该寄存器来存储任何其它的值。
- 由于变量b被指定成输出操作数,当内联汇编语句执行完毕后,它所保存的值将被更新。
|
限定符
|
意义
|
|
"m"、"v"、"o"
|
内存单元
|
|
"r"
|
任何寄存器
|
|
"q"
|
寄存器eax、ebx、ecx、edx之一
|
|
"i"、"h"
|
直接操作数
|
|
"E"和"F"
|
浮点数
|
|
"g"
|
任意
|
|
"a"、"b"、"c"、"d"
|
分别表示寄存器eax、ebx、ecx和edx
|
|
"S"和"D"
|
寄存器esi、edi
|
|
"I"
|
常数(0至31)
|
(转) at&T语法格式 与 at&T - intel格式对比的更多相关文章
- Motorola和Intel格式报文解析的区别
结论:无论用的Motorola,还是Intel格式,只在单个信号跨字节时解析才有区别. 先看下Vector的CANoe中dbc编辑器是如何呈现报文的: 图1 CAN报文中byte与bit顺序 从图 ...
- Intel格式和AT&T格式汇编区别
一.AT&T 格式Linux 汇编语法格式 在 AT&T 汇编格式中,寄存器名要加上 '%' 作为前缀:而在 Intel 汇编格式中,寄存器名不需要加前缀.例如: AT&T 格 ...
- web字体格式及几种在线格式转换工具介绍
原文地址:http://blog.csdn.net/xiaolongtotop/article/details/8316554 目前,文字信息仍是网站最主要的内容,随着CSS3技术的不断成熟,Web字 ...
- [转] Java程序员学C#基本语法两个小时搞定(对比学习)
Java程序员学C#基本语法两个小时搞定(对比学习) 对于学习一门新的语言,关键是学习新语言和以前掌握的语言的区别,但是也不要让以前语言的东西,固定了自己的思维模式,多看一下新的语言的编程思想. ...
- JavaScript中,JSON格式的字符串与JSON格式的对象相互转化
前言:JSON是一个独立于任何语言的数据格式,因此,严格来说,没有“JSON对象”和“JSON字符串”这个说法(然而”菜鸟教程“和”W3school“使用了“JSON对象”和“JSON字符串”这个说法 ...
- 让gcc和gdb支持intel格式的汇编
Linux下的gdb和gcc默认输出的汇编都是AT&T格式的,但是它们都有方式来转换为Intel格式. -masm=[intel|att] 选择intel或AT&T的汇编语法 gcc ...
- [转] 将DOS格式文本文件转换成UNIX格式
点击此处阅读原文 用途说明 dos2unix命令用来将DOS格式的文本文件转换成UNIX格式的(DOS/MAC to UNIX text file format converter).DOS下的文本文 ...
- Linux C++ 调试神技--如何将Linux C++ 可执行文件逆向工程到Intel格式汇编
Linux C++ 调试神技--如何将Linux C++ 可执行文件逆向工程到Intel格式汇编 对于许多在windows 上调试代码的人而言, Intel IA32格式的汇编代码可能并不陌生,因为种 ...
- 【转】将 azw3 格式转换为 mobi 格式并保持原有排版格式
小伙伴多次向 Kindle 伴侣提出一个问题,那就是通过 Calibre 将排版精美的 azw3 格式电子书转换成 mobi 格式后推送到 Kindle,排版格式会发生很大的变化,比如行距过窄.内嵌字 ...
随机推荐
- 用spring boot 2从零开始创建区块链
区块链这么火的技术,大java怎能落后,所以有了本文,主要代码参考自 Learn Blockchains by Building One , 中文翻译:用Python从零开始创建区块链 . 一.区块链 ...
- Shell Step by Step (4) —— Cron & Echo
6.脚本定时任务 # Example of job definition: # .------------------------- minute (0 - 59) # | .------------ ...
- 细说firewalld和iptables
在RHEL7里有几种防火墙共存:firewalld.iptables.ebtables,默认是使用firewalld来管理netfilter子系统,不过底层调用的命令仍然是iptables等. fir ...
- [Java] HashMap 源码简要分析
特性 * 允许null作为key/value. * 不保证按照插入的顺序输出.使用hash构造的映射一般来讲是无序的. * 非线程安全. * 内部原理与Hashtable类似. 源码简要分析 pu ...
- WIN10平板 如何设置不允许切换竖屏
点击右下角的通知,然后点击旋转锁定,即可禁止自动竖屏切换
- 修改QGIS来支持DPI为96的WMTS/WMS服务
缘由 因为各种各种wmts地图客户端产品的标准的支持不一定是一致的,就像ArcGIS不同版本加载WMTS图层的时候计算的规则就有差别(米和经纬度之间转换系数的区别),导致会出现适应各个客户端而出的WM ...
- CentOS yum安装redis(转)
1.安装redis yum install redis 2.安装php-redis扩展 yum install php-redis 3.启动redis,并设定开机自动启动 service redis ...
- IDEA使用笔记(六)——设置项目的JDK配置
1:由于dev分支和master分支的代码差异比较多,所以,就从master上分出一个新的分支dev_,于是我就克隆新的代码,打开对应的项目文件,然后启动试试,发现报出如下的错误,很明显是因为没有制定 ...
- 【C语言】数组名传递给函数,数组的sizeof变为4的原因
C语言中,数组名作为参数传递给函数时,退化为指针,sizeof对指针操作结果应该是4.例子如下: #include<iostream> using namespace std; void ...
- Android在开发中的使用技巧之解决ScrollView嵌套RecyclerView出现的系列问题
根据已上线的app里总结出来的实用小技巧 相信大家都遇到过ScrollView嵌套RecyclerView或者RecyclerView嵌套RecyclerView来使用, 也会遇到一堆奇奇怪怪的问题, ...