本节咱们介绍下intel汇编语法和at&t汇编语法的区别。
以上表中未列出这两种语法在内存寻址方面的差异,个人觉得区别还是很大的,下面单独说说。
在Intel语法中,立即数就是普通的数字,如果让立即数成为内存地址,需要将它用中括号括起来,“[立即数]”这样才表示以“立即数”为地址的内存。
而AT&T认为,内存地址既然是数字,那数字也应该被当作内存地址,所以,数字被优先认为是内存地址,也就是说,操作数若为数字,则统统按以该数字为地址的内存来访问。这样,立即数的地位比较次要了,如果想表示成单纯的立即数,需要额外在前面加个前缀$。
无论是哪种汇编语言风格,都要有访问内存的能力,这就是内存寻址。
咱们之前学习了Intel汇编语法中的很多寻址方式,就内存寻址来说,有直接寻址,基址寻址,变址寻址,基址变址寻址。也可能是习惯了的原因,我个人觉得intel语法真的很直白,容易理解,尤其是在和AT&T的内存寻址相比较之后……
而在AT&T中的内存寻址还是挺独特的,它的内存寻址有固定的格式:
segreg(段基址):base_address(offset_address,index,size)
该格式对应的表达式为:
segreg(段基址):base_address+ offset_address+ index*size。
此表达式的格式和intel 32位内存寻址中的基址变址寻址类似,intel的格式:
segreg:[base+index*size+offset]
不过与intel不同的是,AT&T地址表达式的值是内存地址,直接被当做是内存来读写,而不是普通数字。
看上去格式有些怪异,但其实这是一种“通用”格式,格式中短短的几个成员囊括了它所有内存寻址的方式,任意一种内存寻址方式,其格式都是这个通用格式的子集,都是格式中各种成员的组合。下面介绍下这些成员项。
base_address是基地址,可以为整数,变量名,可正可负。
offset_address是偏移地址,index是索引值,这两个必须是那8个通用寄存器之一。
size是个长度,只能是1、2、4、8(intel语法中也是只能乘以这4个数)。
下面看看内存寻址中有哪些方式,注意,这些方式都是上面通用格式的一部分。
直接寻址:此寻址中只有base_address项,即后面括号中的东东全不要,base_address便为内存啦,比如movl $255,0xc00008F0,或者用变量名:mov $6,var。
寄存器间接寻址:此寻址中只有offset_address项,即格式为(offset_address),要记得,offset_address只能是通用寄存器。寄存器中是地址,不要忘记格式中的圆括号。如mov (%eax), %ebx。
寄存器相对寻址:此寻址中有offset_address项和base_address项,即格式为base_address(offset_address)。这样得出的内存地址是基址+偏移地址之和。
各部分还是要按照格式填写,如movb -4(%ebx),%al,功能是将地址(ebx-4)所指向的内存复制1字节到寄存器al。
变址寻址:此类寻址称为变址的原因是含有通用格式中的变量Index。因为index是size的倍数,所以有index的地方就有size。既然是变址,只要有index和size就成了,base_address和offset_address可有可无,注意,格式中没有的部分也要保留逗号来占位。一共有4种变址寻址组合,下面各举个例子。
无base_address,无offset_address:
movl %eax,(,%esi,2)
功能是将eax的值写入esi*2所指向的内存。
无base_address,有offset_address:
movl %eax,(%ebx, %esi,2)
功能是将eax的值写入ebx+esi*2所指向的内存。
有base_address,无offset_address:
movl %eax,base_value(,%esi,2)
功能是将eax的值写入base_value+esi*2所指向的内存。
有base_address,有offset_address:
movl %eax,base_value(%ebx,%esi,2)
功能是将eax的值写入base_value+ebx+ esi*2所指向的内存。
好啦,AT&T就简单介绍到这,咱们重点是内联汇编。