第5部分-Linux x86 64位汇编 AT&T汇编

第5部分-Linux x86 64位汇编 AT&T汇编

     关于调试我们放到后面,因为这篇开始还是进入本系列的正题了。

    学习了前面的INTEL 汇编,开始使用AT&T汇编了。

    不是所有汇编器使用的标准都一样的,不通汇编器使用不同的汇编语法。

    关于AT&T汇编,也就是基于gas汇编器的。可以参考书籍《Programming Ground Up》。

    AT&T汇编程序的结构跟其它汇编语言类似,由directives, labels, instructions组成,助记符最多可以跟随三个操作数。与Intel汇编语言相比,最大的区别在于操作数的顺序。

这里要提醒的是:这些都会在实例中来学习巩固,死记还是比较难的,在实践中不断理解即可。

    比如Intel汇编语法的传送指令通常是:

        mnemonic destination,source

    在AT&T汇编中,通常是:

        mnemonic source,destination

  • 也即源操作数在左边,目的操作数在右边
  • 所有寄存器前面都要加前缀%.
  • 所有立即数必须冠以前缀$.
  • 符号常数直接引用,引用符号地址在符号前加符号$
  • 通过对操作指令添加b/w/l/q等后缀来指示操作数“尺寸”. Intel 语法通过在内存操作数(而不是操作码本身)前面加 byte ptr、word ptr 和 dword ptr 来指定大小。

jmp, call, ret这些指令用于控制程序从某条指令跳到另外的指令处。它又分为近跳转(在同一段内)和远跳转(不同段内)。跳转地址可以用相对偏移(label),寄存器,内存操作数.

  • 中间形式长跳转和调用是 lcall/ljmp $section, $offset;Intel 语法是 call/jmp far section:offset。在 AT&T 语法中,远返回指令是 lret $stack-adjust,而 Intel 使用 ret far stack-adjust。
  • GAS中的内存操作数的寻址方式是section:disp(base, index, scale)。%segment:ADDRESS (, index, multiplier)或%segment:(offset, index, multiplier)或%segment:ADDRESS(base, index, multiplier)。ADDRESS or offset + base + index * multiplier。NASM 使用的语法比较简单。上面的公式在 NASM 中表示为:Segment:[ADDRESS or offset + index * multiplier]
  • GAS 中,重复结构以.rept指令开头,用一个.endr指令结束这个指令。.rept后面是一个数字,指定.rept/.endr结构中表达式重复执行的次数。相当于编写这个指令count次,每次重复占据单独的一行。NASM 中,在预处理器级使用相似的结构。它以 %rep 指令开头,以%endrep结尾。%rep指令后面是一个表达式。NASM 中还有另一种结构,times指令。与%rep相似,它也在汇编级起作用。

    在AT&T语法中,符号扩展和零扩展指令的格式为,基本部分"movs"和"movz"(对应Intel语法的movsx和movzx),后面跟源操作数长度和目的操作数长度。movsbl意味着movs (from)byte (to)long;movsbw意味着movs (from)byte (to)word;movswl意味着movs (from)word (to)long。对于movz指令也一样。

    以点号开头的任何内容都不会直接转换为机器指令。例如.section .data表示数据段,.section .text表示代码段,.globl意味着汇编程序在汇编后不应丢弃此符号,因为链接器将需要它。 _start是一个特殊的符号,总是需要用.globl标记,因为它标记了程序开始的位置。

    函数定义.type funcname,@function,定义函数。

  • GAS 中的汇编器指令以 “.” 开头,但是在 NASM 中不是。
  • GAS 支持 C 风格(/* */)、C++ 风格(//)和 shell 风格(#)的注释。NASM 支持以 “;” 字符开头的单行注释。
  • NASM 分别使用 dd、dw 和 db 指令声明 32 位、16 位和 8 位数字,而 GAS 分别使用 .long、.int 和 .byte。GAS 还有其他指令,如 .ascii、.asciz 和 .string。在 GAS 中,像声明其他标签一样声明变量(使用冒号),在 NASM 中,只需在内存分配指令(dd、dw 等等)前面输入变量名,后面加上变量的值。
  • 内存直接寻址模式。NASM 使用方括号间接引用一个内存位置指向的地址值:[var1]。GAS 使用圆括号间接引用同样的值:(var1)
  • 字符串的地址 ,在 NASM 中,内存变量代表内存位置本身,所以 push str 这样的调用实际上是将地址压入堆栈的顶部。在 GAS中,变量 str 必须加上前缀 $,才会被当作地址。如果不加前缀 $,那么会将内存变量代表的实际字节,而不是地址。
  • 关于注释,Nasm是;,而在AT&T中是# 单行注释;// 单行注释;/* */ 多行注释

当然这些都会在实例中来学习巩固,死记还是比较难的,实践中不断理解即可。

数据声明

AT&T中数据声明如下:

命令 数据类型

.ascii 文本字符串

.asciz 以空字符串结尾的文本字符串

.byte  字节值

.double       双精度浮点数

.float 单精度浮点数

.int    32位整数

.long 32位整数(同32)

.octa  16字节整数

.quad 8字节整数

.short 16位整数

.single        单精度浮点数(和.float同)

 

此外汇编器使用两个命令声明缓冲:

命令 描述

.comm        声明未初始化的数据的通用内存区域

.lcomm       声明未初始化的数据的本地通用内存区域

movx,其中x可以是下面字符:

x       描述

q   用于64位的长字值

l        用于32位的长字值

w      用于16位的字值

b       用于8位的字节值

后面我们会给出几个常用的AT&T语法汇编例子。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章