冯诺依曼计算机,将计算机分为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
总结一下内存寻址方式
- 1000
- 1000(%eax)
- 1000(,%edx,4)
- 1000(%eax,%edx)
- 1000(%eax,%edx,4)
- (%eax)
- (%eax,%edx)
- (%eax,%edx,4)
- (,%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版权协议,转载请附上原文出处链接和本声明。