作者:冯老师,华清远见嵌入式学院讲师。

译自“Using as The GNU Assembler January 1994”。

参考Tornado随机文档“GNU Toolkit User's Guide"。

GNU Assembler

80386 Dependent Features

■ AT&T语法 vs. Intel语法

为了保持和gcc的输出的兼容性,as支持AT&T System V/386汇编语法,它和Intel语法有相当大的差别。强调这个是因为几乎所有的80386文档只使用Intel语法。两者之间的显著区别是:

● AT&T的立即数有前缀'$',Intel的立即数没有前缀(Intel 'push 4'为AT&T 'push Û)。AT&T的寄存器有前缀'%',Intel的寄存器没有前缀。AT&T的绝对跳转(和相对PC的跳转相反)jump/call操作 数有前缀'*',Intel没有前缀。

● AT&T和Intel语法的源和目的操作数的顺序相反。Intel的'add eax, 4'等效于AT&T的'addl Û, %eax'。使用'source, dest'规范的目标是为了和以前的Unix汇编器保持兼容。

● AT&T语法中的内存操作数的宽度是根据操作码名称的最后一个字符决定的。操作码后缀'b','w',和'l'指定了byte(8- bit),word(16-bit),和long(32-bit)的内存引用。Intel语法则对内存操作数(不是操作码)加前缀:'byte ptr','word ptr'和'dword ptr'。这样,Intel 'mov al, byte ptr foo'等效于AT&T的'movb foo, $al'。

● AT&T中的long jumps和calls的立即形式为'lcall/ljmp $section, $offset';Intel语法为'call/jmp far section:offset'。同样,AT&T的远程返回指令为'lret $stack-adjust',而Intel格式为'ret far stack-adjust'。

● AT&T汇编器不提供对多节(multiple section)程序的支持。Unix风格的系统希望所有的程序都是单节的。

■ 操作码命名(opcode naming)

操作码前有一个字符的后缀,指定了操作数的宽度。字母'b','w',和'l'指定了byte,word, 和long型的操作数。如果指令中没有后缀并且不包含内存操作数,那么as将基于目标寄存器操作数(指令中的最后一个寄存器)填充这个缺少的后缀。所 以,'mov %ax, %bx'等效于'movw %ax, %bx';同样,'mov Û, %bx'等效于'movw Û, %bx'。注意这个特点不和AT&T的Unix汇编器兼容,后者假定缺少的后缀为long型操作数宽度。(这个不兼容型并不影响编译器的输出,因 为编译器总是显式地指定操作码后缀。)

AT&T和Intel中的操作码的格式几乎全部一样,但有一个例外。AT&T的符号扩展 (sign extend)和零扩展(zero exten)指令需要指定2个宽度,一个宽度用来指定sign/zero扩展的from,另一个用来零扩展to。在AT&T语法中使用2个操作码 后缀。符号扩展和零扩展的基本名称是'movs...'和'movz...'(Intel格式为'movsx'和'movzx')。操作码后缀加在这个基 本名称后,from在之前。所以,AT&T语法中'movxbl %al, %edx'意思为”move sign extend from %al to %edx“。所以可能的后缀有'bl'(从byte到long),'bw'(从byte到word),和'wl'(从word到long)。

Intel风格的指令:

● 'cbw' - 符号扩展byte '%al'到word '%ax',

● 'cwde' - 符号扩展word '%ax'到long '%eax',

● 'cwd' - 符号扩展word '%ax'到long '%dx:%ax',

● 'cdq' - 符号扩展dword '%eax'到quad '%edx:%eax',

在AT&T中分别叫'cbtw','cwtl','cwtd',和'cltd'。

远程call/jump指令在AT&T中分别为'lcall'和'ljmp',而Intel的格式为'call far'和'jump far'。

■ 寄存器命名(register naming)

寄存器操作数总有前缀'%'。80386的寄存器包括:

● 8个32-bit寄存器 '%eax'(accumulator),'%ebx','%ecx','%edx','%edi','%esi','%ebp'(<I>frame</I> pointer),和'%esp'(stack pointer)。

● 8个低16-bit的以上寄存器:'%ax','%bx','%cx','%dx','%di','%si','%bp',和'%sp'。

● 6个节寄存器'%cs'(代码节),'%ds'(数据节),'%ss'(堆栈节),'%es', '%fs',和'%gs'。

● 3个处理器控制寄存器'%cr0','%cr2',和'%cr3'。

● 6个调试寄存器'%db0','%db1','%db2','%db3','%db6',和'%db7'。

● 2个测试寄存器'%tr6'和'%tr7'。

● 8个浮点寄存器栈'%st'或等效的'%st(0)','%st(1)','%st(2)','%st(3)','%st(4)','%st(5)','%st(6)',和'%st(7)'。

■ 操作码前缀(opcode prefixes)

操作码前缀用于修改以下操作码。它们用于重复字符串指令,提供节覆盖(section overrides),执行总线锁定操作,以及给出操作数和地址的宽度(对于通常的32-bit操作数,可以使用一个”操作数宽度“操作码前缀,来指定 16-bit的操作数)。操作码前缀通常占据一行,没有操作数,并且必须直接位于它们所作用于的指令之前。例如'scas'(字符串扫描)指令可以这样重 复:

repne

scas

下面列出操作码前缀:

● 节覆盖前缀'cs','ds','ss','es','fs','gs'。

● 操作数/地址宽度前缀'data16'和'addr16',将32-bit的操作数/地址改变为16-bit的操作数/地址。注:16-bit寻址模式(即8086和80286寻址模式)还没有支持。

● 总线锁定前缀'lock',在执行它修饰的指令时禁止中断。(只对特定指令有效,参考80386指令手册。)

● 等待协处理器指令'wait',等待协处理器完成当前指令。对于80386/80387组合这不再需要。

● 'rep','repe',和'repne'前缀用来修饰字符串指令,使它们重复'%ecx'次。

注:操作码前缀(1字节):

0xF0 - LOCK;

0xF2 - REPNE/REPNZ(只用于字符串指令);

0xF3 - REP(只用于字符串指令);

0xF3 - REPE/REPZ(只用于字符串指令);

0xF3 - Streaming SIMD扩展指令;

段前缀:

0x2E - CS段覆盖;

0x36 - SS段覆盖;

0x3E - DS段覆盖;

0x26 - ES段覆盖;

0x64 - FS段覆盖;

0x65 - GS段覆盖。

操作数宽度覆盖:0x66

操作数宽度覆盖:0x66

■ 内存引用(memory references)

Intel语法中间接内存引用的形式为:

section:[base + index*scale + disp]

等效的AT&T语法为:

section:disp(base, index, scale)

其中base和index分别为可选的、32-bit的基址和索引寄存器;disp为可选的偏移 (displacement),scale的取值为1,2,4,和8,乘以index计算操作数的地址。如果不指定scale,scale取值为1。 section指定了内存操作数的可选的节寄存器,它可以覆盖缺省的节寄存器(参考80386手册中的节寄存器的缺省值)。注意AT&T语法中的 节覆盖必须有'%'前缀。如果指定的节覆盖碰巧和缺省的节寄存器相同,那么as并不输出任何节寄存器覆盖前缀。所以,可以使用节寄存器覆盖来强调给定的内 存操作数的节寄存器。

下面是Intel和AT&T的内存引用的例子:

AT&T:'-4(%ebp)',Intel:'[ebp-4]';

base是'%ebp',disp为'-4'。使用缺省的节(%ss)。index和scale缺省。

AT&T:'foo(,%eax,4)',Intel:'[foo + eax*4]';

index为%eax(scale为4),disp为'foo'。节寄存器缺省为%ds。

AT&T:'foo(,1)',Intel:'[foo]';

使用foo指向的值当作内存操作数。注意base和index都缺省,但只有一个',',这是一个语法例外。

AT&T:'%gs:foo',Intel:'gs:foo'。

绝对的call和jump的操作数必须有前缀'*'。如果不指定前缀,as选择PC(program counter)相对寻址。

任何有内存操作数的指令必须指定它的宽度(byte,word,long),使用操作码后缀('b','w','l')。

■ 跳转指令的处理(handling of jump instrucion)

跳转指令总是使用最小可能的偏移(displacement)进行优化。处理方法是,如果目标地址足够近, 那么使用字节(8-bit)偏移的跳转。如果字节偏移不够,那么使用long(32-bit)偏移。不支持word(16-bit)偏移跳转(即在跳转指 令前加'addr16'操作码前缀),这是因为80386坚持,如果使用word偏移那么%eip将被掩码为16-bit。

注意'jcxz','jecxz','loop','loopz','loope','loopnz'和 'loopne'指令只使用byte偏移,所以如果你使用这些指令(gcc不使用),你会得到一个错误消息(以及不正确的代码)。AT&T对这个 问题的解决是扩展'jcxz foo'为:

jcxz    cx_zero

jmp     cx_nonzero

cx_zero:

jmp     foo

cx_nonzero:

■ 浮点(floating point)

(omitted)

■ 写16-bit代码(wrting 16-bit code)

GAS除了支持”纯“32-bit i386代码外,还提供对实模式和16-bit保护模式代码段的有限支持。

(to be continued)

文章来源:华清远见嵌入式学院原文地址:http://www.embedu.org/Column/Column854.htm

更多相关嵌入式免费资料查看华清远见讲师博文>>

GNU for x86汇编语法的更多相关文章

  1. GNU风格 ARM汇编语法指南

    汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设置页表.操作 ARM的协处理器等.这些初始化工作完成后就可以跳转到C代码main函数中执行. 1.  GNU汇编语言语句格式 任何Linux汇编 ...

  2. GNU风格 ARM汇编语法5

    . GNU汇编程序中的常数 <>十进制数以非0数字开头,如:123和9876: <>二进制数以0b开头,其中字母也可以为大写: <>八进制数以0开始,如:,: &l ...

  3. GNU风格 ARM汇编语法2

    .GNU汇编程序中的标号symbol(或label) 标号只能由a-z,A-Z,-,".",_等(由点.字母.数字.下划线等组成,除局部标号外,不能以数字开头)字符组成. Symb ...

  4. (转)GNU风格ARM汇编语法指南(非常详细)5

    原文地址:http://zqwt.012.blog.163.com/blog/static/120446842010111482417545/ 6.GNU汇编程序中的常数 <1>    十 ...

  5. (转)GNU风格ARM汇编语法指南(非常详细)2

    原文地址:http://zqwt.012.blog.163.com/blog/static/120446842010111481828392/ 2.GNU汇编程序中的标号symbol(或label) ...

  6. GNU风格 ARM汇编语法1

    汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设置页表.操作 ARM的协处理器等. 这些初始化工作完成后就可以跳转到C代码main函数中执行. 1.GNU汇编语言语句格式 任何Linux汇编行 ...

  7. (转)GNU风格ARM汇编语法指南(非常详细)1

    原文地址:http://zqwt.012.blog.163.com/blog/static/120446842010111481551809/ 汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设 ...

  8. GNU风格 ARM汇编语法4

    .GNU汇编语言定义入口点 汇编程序的缺省入口是_start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点. 例:定义入口点 .section .data < initializ ...

  9. GNU风格 ARM汇编语法3

    . GNU汇编程序中的分段 <1>.section伪操作 .section <section_name> {,”<flags>”} Starts a new cod ...

随机推荐

  1. 10g 11g配置Logical Standby

    1.创建一个物理Standby数据库 详细见11g Physical Standby配置 2.Standby数据库取消managed  recovery ALTER DATABASE RECOVER ...

  2. jQuery插件treeview点击节点名称不展开、收缩节点 分类: JavaScript 2014-06-16 20:28 539人阅读 评论(0) 收藏

    修改jquery.treeview.js文件中的applyClasses方法(注释掉两行代码): 修改后的applyClasses方法如下: applyClasses: function(settin ...

  3. Win10 for Phone 裁剪保存

    //StorageFolder savedPics = ApplicationData.Current.LocalFolder; //BitmapImage bi = new BitmapImage( ...

  4. ApexSQL Log-SQL误操作恢复工具

    今天不小心对数据库执行了一次误操作,心想有没有什么工具能恢复这次误操作呢?于是找到了Log Explorer 4.2,可惜它最多只支持SQL 2005,在SQL 2008上无法使用,然后又找到了Ape ...

  5. win7 快捷键

    F F1 显示辅助 F2 重命名选定项目 F3 搜索文件或文件夹 F4 在 Windows 资源管理器中显示地址栏列表 F5 刷新活动窗口 F6 在窗口中或桌面上循环切换屏幕元素 F10 激活活动程序 ...

  6. python学习第三天

    小结: 总体上,python是解释型语言,开源比较好,速度较慢,装逼神器,解释器较常用的是CPython,安装后python进入运行环境 exit()退出 第一个hello world : print ...

  7. 数字信号处理实验(一)——DTFT

    1.MATLAB自编绘图函数 function [] = signal_write(X,w,flag) % X:数据 % w:频率向量 magX=abs(X);angX=angle(X); realX ...

  8. 【转】Struts2解决表单重复提交问题

    用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此,重复提 ...

  9. 【JSON 注解】JSON循环引用1-----Jackson常用注解介绍 eq:@JsonIgnore

    循环引用:实体A与实体B有关系,A中有B作为字段,B中有A作为一个字段.查询A对象后,将A对象转化为JSON格式数据时,会因为序列化过程中导致A中有B字段,B字段中又有A,这样就引起了循环引用的问题! ...

  10. 【转】【技术博客】Spark性能优化指南——高级篇

    http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...