汇编语言:mov指令,寄存器,寻址

冯诺依曼计算机,将计算机分为5大部件:运算器,控制器,存储器,输入设备,输出设备。运算器和控制器共同执行指令。指令和数据一样,保存为二进制数据。运算器和控制器共同组成CPU,CPU执行机器指令,也就是二进制数。机器指令难于阅读,编写。所以人们用英语单词来表示机器语言,这种方式被称为汇编语言。

 用汇编语言编程就是在和立即数,寄存器,内存在打交道。

寄存器有8个,EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP。

内存有不同的寻址方式,下面会详细说明。

movb

复制字节数据。

mov指令有两个操作数,源操作数和目标操作数。源操作数可以为立即数,寄存器,内存地址,目的操作数可以为寄存器,内存地址。两者不能同时为内存地址。

所有5种变化:

movb $1,%eax

movb $1,list

movb %al,%cl

movb %al,list

movb list,%al

.section .data
    list:.byte 0,0,0,0,0,0,0,0,0,0,0,0,0

.section .text
.global main

main:
    pushl %ebp
    movl %esp,%ebp

    movb $'H',list
    movb $'E',list+1
    movb $'L',list+2
    movb $'L',lis+3
    movb $'O',list+4
    movb $',',list+5
    movb $'W',list+6
    movb $'O',list+7
    movb $'R',list+8
    movb $'L',list+9
    movb $'D',list+10
    movb $'\n',list+11  
    movb $'\0',list+12

    pushl $list
    call printf
    addl $4,%esp
    
    movl %ebp,%esp
    popl %ebp
    ret

movb $'H',list  是直接寻址,代码用数字给出了内存地址,下面的movb都是直接寻址。list在汇编和链接后会是一个内存地址,list+1在list的后一个字节。

gcc hello.s -o hello
./hello

输出:
HELLO,WORLD

除了用直接寻址,还可以寄存器间接寻址

.section .data
    list:.byte 0,0,0,0,0,0,0,0,0,0,0,0,0

.section .text
.global main

main:
    pushl %ebp
    movl %esp,%ebp
    
    movl $list,%eax
    movl $'H',(%eax)
    addl $1,%eax
    movl $'E',(%eax)
    addl $1,%eax
    movl $'L',(%eax)
    addl $1,%eax
    movl $'L',(%eax)
    addl $1,%eax
    movl $'O',(%eax)
    addl $1,%eax
    movl $',',(%eax)
    addl $1,%eax
    movl $'W',(%eax)
    addl $1,%eax
    movl $'O',(%eax)
    addl $1,%eax
    movl $'R',(%eax)
    addl $1,%eax
    movl $'L',(%eax)
    addl $1,%eax
    movl $'D',(%eax)
    addl $1,%eax
    movl $'\n',(%eax)
    addl $1,%eax
    movl $'\0',(%eax)
    addl $1,%eax
    
    pushl $list
    call printf
    addl $4,%esp
    
    movl %ebp,%esp
    popl %ebp
    ret

内存寻址的一般公式是:address(寄存器1,寄存器2,比例因子)。比例因子可以为1,2,4,8。内存地址为address+寄存器1的值+寄存器2的值*比例因子。其中的元素可以省略。直接寻址省略了(寄存器1,寄存器2,比例因子)。寄存器间接寻址省略了address,寄存器2,比例因子。

下面为基址寻址

.section .data
    list:.byte 0,0,0,0,0,0,0

.section .text
.global main

main:
    pushl %ebp
    movl %esp,%ebp
    
    movl $0,%eax
    movl $'H',list(%eax)
    addl $1,%eax
    movl $'E',list(%eax)
    addl $1,%eax
    movl $'L',list(%eax)
    addl $1,%eax
    movl $'L',list(%eax)
    addl $1,%eax
    movl $'0',list(%eax)
    addl $1,%eax
    movl $'\n',list(%eax)
    addl $1,%eax
    movl $'\0',list(%eax)
    addl $1,%eax
    
    pushl $list
    call printf
    addl $4,%esp
    
    movl %ebp,%esp
    popl %ebp
    ret

基址加变址

.section .data
    list:.byte 0,0,0,0

.section .text
.global main

main:
    pushl %ebp
    movl %esp,%ebp
    
    movl $list,%eax
    movl $0,%edx
    
    movl $'a',(%eax,%edx)
    addl $1,%edx
    movl $'b',(%eax,%edx)
    addl $1,%edx
    movl $'c',(%eax,%edx)
    addl $1,%edx
    
    pushl $list
    call printf
    addl $4,%esp
    
    movl %ebp,%esp
    popl %ebp
    ret

movl

复制四字节数据

其他寻址方式

.section .rodata
    .LC0:.string "%d %d %d\n"
.section .data
    list:.int 0,0,0
.section .text
.global main

main:
    pushl %ebp
    movl %esp,%ebp
    
    movl $2,%eax
    movl $200,list(,%eax,4)    //变址比例因子寻址
    
    movl $list,%eax
    movl $1,%edx
    movl $100,(%eax,%edx,4)    //基址加变址寻址
    
    movl $0,%eax
    movl $0,%edx
    movl $1,list(%eax,%edx,4)   //基址加变址寻址
    
    pushl list+8
    pushl list+4
    pushl list
    pushl $.LC0
    call printf
    addl $16,%esp
    
    
    movl %ebp,%esp
    popl %ebp
    ret
gcc hello.s -o hello
./hello
输出:
1 100 200

总结一下内存寻址方式

  1. 1000
  2. 1000(%eax)
  3. 1000(,%edx,4)
  4. 1000(%eax,%edx)
  5. 1000(%eax,%edx,4)
  6. (%eax)
  7. (%eax,%edx)
  8. (%eax,%edx,4)
  9. (,%edx,4)

movw

复制2个字节

.section .rodata
    .LC0:.string "%x \n"
    
.section .data
    list .short 0,0

.section .text
.global main

main:
    pushl %ebp
    movl %esp,%ebp
    
    movw $0x1122,list
    movw $0x3344,list+2
    
    pushl list
    pushl $.LC0
    call printf
    addl $8,%esp
    
    movl %ebp,%esp
    popl %ebp
    ret

 

 

 

 


版权声明:本文为pk_20140716原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。