《深入理解计算机系统》(1) AT&T汇编指令

版权声明:嘤嘤嘤 https://blog.csdn.net/HNUCSEE_LJK/article/details/88543259

汇编指令初步

机器指令是CPU能直接识别并执行的指令,它的表现形式是二进制编码,如00001001010101100110010000101011。用机器指令编写出来的程序执行效率高,没有多余的额外操作。但由于机器指令十分复杂,难以记忆,且不方便阅读和修改,容易产生错误,所以设计了汇编指令,通过一些能反映机器指令功能的单词或词组来代表该机器指令,而不再关心机器指令的具体二进制编码。与此同时,汇编指令也把CPU内部的各种资源符号化,使用该符号名也等于引用了该具体的物理资源。

寄存器

80386提供以下其中不同类型的32位寄存器

通用寄存器

  • EAX:累加器(Accumulate),是算术运算的主要寄存器
  • EBX:基址寄存器(Base),在内存中寻址时存放基址
  • ECX:计数器(Counter)
  • EDX:数据寄存器(Data)
  • ESI:源变址
  • EDI:目标变址
  • ESP:堆栈指针
  • EBP:基址指针

以上通用寄存器的低16位又构成一个16位寄存器,以兼容更短的指令,分别为:AX、BX、CX、DX、SI、DI、SP、BP。而AX、BX、CX、DX又可划分为两个8位的寄存器,分别为AH和AL,BH和BL,CH和CL,DH和DL,它们实际上是相应的16位寄存器的高8位和低8位。

段寄存器

  • CS:代码段寄存器
  • SS:堆栈段寄存器
  • DS:数据段寄存器
  • ES、FS、GS:附加数据段寄存器

指令指针寄存器和标志寄存器: EIP、EFLAGS

系统表寄存器: GDTR、IDTR、LDTR、TR

控制寄存器: CR0、CR1、CR2、CR3、CR4

调试寄存器: DR0、DR1、DR2、DR3、DR4、DR5、DR6、DR7

测试寄存器: TR6、TR7

AT&T汇编代码概览

格式:指令 源操作数, 目的操作数

示例:movl  $8, %eax

操作数可分为立即数(immediate)、寄存器(register)操作数存储器(memory)操作数。立即数不必存储于寄存器或存储器中,可以直接出现在指令中,不可作为目的操作数,相当于高级语言中的常量,使用立即数时,需要在立即数前加上$;CPU计算总是仅从寄存器直接存/取数据,寄存器操作数可作为源操作数或目的操作数,引用寄存器操作数时需要在寄存器名称前加上%

还有一种符号常量,可以直接引用,相当于高级语言中的变量。引用符号常量的地址时需要在符号常量前加上$

操作数的长度通过为指令添加后缀来指定:

  • b:byte,长度为8位
  • w:word,长度为16位
  • l:long-word,长度为32位
  • q:quad-word,长度为64位

如mov指令,添加后缀l后的movl表示传送32位的长字值。如果指令没有指定操作数长度,那么编译器将自动设置为目标操作数的长度;如果指令没有指定操作数长度,而编译器又无法猜测操作数长度,编译器则会报错,如指令"push $1"。

Linux下一个简单的AT&T汇编代码示例:

.section .data  #.section .data段用来申明变量
    value1:
        .int 1 
    value2:
        .short 2
    value3:
        .byte 3

.section .text   
#.ascii 文本字符串
#.asciz 以空字符结尾的文本字符串
#.byte  字节
#.double双精度浮点数
#.float 单精度浮点数
#.int
#.long	32位整数
#.octa	16字节整数
#.quad	8字节整数
#.short	16位整数
#.single 同float

.global _start   
 _start:      
     nop
     movl $100, %ecx
     movl %ecx, value2
     movw $20, value2

	 
     movl $1, %eax  
     movl $0, %ebx  
     int $0x80  

附上一些Linux下gdb调试的指令:

  • print &value,查看value变量在内存中的地址 
  • x /4bt + 内存地址,查看内存内容(b表示单字节,h表示双字节, w表示四字节,g表示八字节)( x 按十六进制格式显示变量。d 按十进制格式显示变量。 u 按十六进制格式显示无符号整型。o 按八进制格式显示变量。 t 按二进制格式显示变量。a 按十六进制格式显示变量。 c 按字符格式显示变量。f 按浮点数格式显示变量。)

间接寻址

当寄存器中保存的是内存地址时,它就被称为指针。通过指针可进行间接寻址,称为寄存器间接寻址,格式为size(%register)。括号内的是寄存器,括号外size是偏移值,可为负数。最终表示的地址为寄存器%register中的值 + size

变址寻址

变址寻址适合访问内存中的连续数据,比如数组。变址寻址的格式为offset_address(base_address, index, size),最终表示的地址为base_address + offset_address + index*size。其中,offset_address为偏移量,base_address为基址(比如数组首地址),index为变址。base_address和index必须为寄存器,size的值必须为2的次幂(1, 2, 4, 8...)。如果其中的任何值为0,可以忽略,但必须有逗号作为占位符

.section .data
    value1:
        .int 400
    values:
        .int 400,15,20,25,30,35,40,45,50,55,60
		
.section .text    
   
.global _start   
 _start:      
    nop
    movl $1, %edi
    movl $4, %ebx
    movl $2, %edi
    movl value1, %ecx
    movl values, %eax
    movw values, %cx
    movb values, %ch

    movl values(, %edi, 4), %eax
    movl values(%edi, %ebx, 1), %eax
    #movl values(, %edi, 3), %eax
    # offset_address(base_address, index, size)
    # base_address + offset_address + index*size
    # 其中base_address和index的值必须为寄存器
    # 如果其中的任何值为0,可以忽略,但必须有逗号作为占位符	
	
    movl $1, %eax  
    movl $0, %ebx
    int $0x80  

一些指令 

  • mov S, D:数据传送指令,表示D <-- S。
  • lea S, D:mov指令的变形。 lea 指令形式是从存储器读数据到寄存器,但实际并没有引用存储器,而是将有效地址写入目的操作数(D必须是寄存器) ,表示D <-- &S。举个例子:若寄存器%edx的值为x,那么 leal 7(%edx,%edx,4), %eax 表示寄存器%eax的值为5x+7。lea执行效率很高,且常用来执行简单的算术操作,比如模拟一些三元运算。举个例子,若要实现%ebx = %eax + %edx,不使用lea需要多条指令,而使用lea只需lea(%eax, %edx, 1), %ebx一条指令。

lea与mov的区别

 leaq 8(%edi), %eax ==> R[%eax] = 8 + R[%edi]

movq 8(%edi), %eax ==> R[%eax] = M[8 + R[%edi]]

  •  jmp label:无条件跳转指令,跳转到label。
.section .text    
   
.global _start   
 _start:      
     nop
     movl $0xffffffff, %eax
     jmp exit
     movl $5, %eax

 exit:  	
     movl $1, %eax   
     int $0x80  
  • push S:压栈。对于pushl S,表示R[%esp] <-- R[%esp] – 4;M[R[%esp]] <-- S(4为l的字节长,假设栈往低地址扩展)。
  • pop D:出栈。对于pop D,表示D <-- M[R[%esp]];R[%esp] <-- R[%esp] + 4。
.section .data
    value:
        .int 0x87654321
.section .text    
   
.global _start   
 _start:      
    nop
    movl $0x12345678, %ebx
    push %ebx
    #pushl %ebx #%ebx的长度可判断, 故l也可省略
    pushw %bx
    pushw value
    push $value
    #pushb %ah 

    popl %ebx
    popl %eax
    popw %cx
		
    movl $1, %eax   
    int $0x80  

猜你喜欢

转载自blog.csdn.net/HNUCSEE_LJK/article/details/88543259
今日推荐