当前位置: 首页 > 要闻

环球今日报丨计算机程序基础教程(03):x86读写数据指令

来源:哔哩哔哩 发布时间:2023-02-09 04:04:50

【mov指令】

mov指令用于读写寄存器和内存地址空间,有两个地址码,分别指定写入地址与读取地址,寻址方式有3种:立即寻址、寄存器寻址、内存寻址。


(资料图)

● 立即寻址

也称为立即数寻址,写入的数据存储在地址码中,示例:mov ax,99,将99写入ax寄存器,其中99直接存储在地址码中。

立即数可以使用多种进制方式指定,如下:

99,默认为10进制

10B,添加B后缀,表示2进制

67Q,添加Q后缀,表示8进制

0CH,添加H后缀,表示16进制,若第一个数字为字母则需要额外添加前缀0

0xC,添加0x前缀,表示16进制,某些编译器不支持此方式

● 寄存器寻址

要操作的数据存储在寄存器中,示例:mov ax,bx,将bx中的数据写入ax。

● 内存寻址

要操作的数据在内存中,地址码指定数据的偏移地址,段地址默认存储在ds寄存器中,可以在内存与寄存器之间读写数据,也可以将一个立即数写入到内存,但是不能在两个内存地址之间读写数据。

★ 直接内存寻址

直接内存寻址使用一个立即数指定偏移地址,要操作的内存地址不能改变。

示例:

mov ax,[0x404020]      ;将0x404020地址处的数据写入ax寄存器,使用ds作为段地址寄存器。

在寄存器与内存之间读写时,处理器默认要读写的数据长度与寄存器长度相同,处理器通过寄存器的长度确定要读写多少个内存单元。

将一个立即数写入内存时,需要在地址码中指定数据的长度,处理器通过操作数类型码确定要写入几个内存单元。

指定数据长度关键词如下:

byte,1字节

word,2字节

dword,4字节

fword,6字节

qword,8字节

示例:

mov byte[0x404020],9   ;将9写入地址0x404020处,占1个存储单元

mov word[0x404020],9   ;占用2个存储单元

以上为nasm编译器语法,masm编译器需要额外添加ptr关键词:byte ptr。

★ 间接内存寻址

地址码中指定一个寄存器,使用寄存器中的数据作为偏移地址,寄存器中的数据也称为指针,意为它指向另一个数据,需要读写其他内存地址时,读写数据指令无需修改,只需要修改指针的值即可。

示例:

mov ax,[bx]     ;[]符号内指定一个寄存器,读取寄存器中的数据作为偏移地址

mov ax,[rcx]    ;在x86-64中,第二个地址码只能使用32位、64位寄存器

偏移地址也可以使用多个数据组合的方式指定:

mov eax, [rbx+2]        ;寄存器+立即数

mov eax, [rbx+rsi]      ;寄存器+寄存器

mov eax, [rbx+rsi+2]    ;寄存器+寄存器+立即数,两个寄存器长度必须相同

mov eax, [rbx*4+2]      ;寄存器×立即数+立即数

mov eax, [rbx*4+rcx]    ;寄存器×立即数+寄存器

● 字节序

对于长度超过一字节的数据,需要使用多个存储单元存储,不同处理器对数据字节的排序方式不同,x86处理器规定数据的低位存储在低地址中,高位存储在高地址中,比如 12345678H 需要占用4个存储单元,拆分为 12H、34H、56H、78H 四个字节,78H是低位,放在低地址中,12H放在高地址中,这种排序方式称为小端序,反之则称为大端序。

【读写并运算】

lea指令的原意为将一个指针写入一个寄存器,功能与mov类似,但是lea不能使用内存寻址,只能使用寄存器寻址、立即数寻址。

lea rax,[0x4]    ;将一个立即数写入rax,数据放在[]符号内,但这并非表示内存寻址

lea rax,[rbx]    ;将rbx中的数据写入rax,在x86-64中不能使用32位以下寄存器

lea的上述功能与mov指令重合,这并非lea的全部使用方式,lea支持读取数据的同时对数据进行运算,比如:lea rax,[rbp+4],rbp中的数据+4写入rax,等同于如下指令的组合:

mov rax, rbp

add rax, 4

lea支持以下数据运算方式:

lea  rax, [rbx+2]

lea  rax, [rbx+rcx]

lea  rax, [rbx+rcx+2]

lea  rax, [rbx*4+2]

lea  rax, [rcx+rbx*4]

【读写并扩展】

● movzx

movzx指令用于将一个无符号数扩展长度并写入指定寄存器,扩展的长度由写入寄存器的长度决定,具体行为是将扩展后的高位全部使用0填充,需要扩展的数据可以使用寄存器寻址、内存寻址,若使用内存寻址则需要指定数据长度。

movzx ax, al               ;al扩展为ax,ax高位全部设置为0

movzx eax, al

movzx eax, ax

movzx eax, bx

movzx rax, byte[0x404020]

movzx不能用于将32位寄存器数据扩展为64位长度,比如 movzx rax,eax 这样是错误的,因为写入eax时rax的高位会清0,无需扩展,直接使用即可,但是写入ax时eax的高位不会清0,这是x86-64与x86的一个区别。

● movsx

movsx指令用于读取并扩展一个有符号数的长度,具体行为是将扩展长度数据的符号位写入扩展后高位的每一位,若是正数,则高位全部使用0填充,若是负数,则高位全部使用1填充,其中最高位的1表示符号位,其余高位的1表示负数补码,将扩展高位全部设置为1即可满足两个补数相加产生进位的规则。

movsx ax, al                ;ax的高8位为al的符号位,若al为负数,则ax的高8位全部为1

movsx eax, al

movsx eax, bx

movsx rax, ebx

movsx rax, byte[0x404020]

【数据扩展指令】

数据扩展指令用于将ax系列寄存器中的有符号数扩展长度。

★ cbw

将al寄存器中的8位有符号数扩展为16位,使用ax寄存器存储,al存储低位,ah存储高位,具体行为是将al寄存器中的符号位写入ah的每一位,若al为负数则ah存储负数补码的高8位。

★ cwde

将ax中的16位有符号数扩展为32位,使用eax存储。

★ cdqe

将eax中的32位有符号数扩展为64位,使用rax存储。

★ cwd

将ax中的16位有符号数扩展为32位,使用dx+ax存储,dx存储高位,ax存储低位。

★ cdq

将eax中的32位有符号数扩展为64位,使用edx+eax存储,edx存储高位,eax存储低位。

★ cqo

将rax中的64位有符号数扩展为128位,使用rdx+rax存储,rdx存储高位,rax存储低位。

【数据交换】

xchg指令用于将两个地址码中的数据进行交换,可以使用寄存器寻址、内存寻址,但是不能使用两个内存地址,这一点与mov相同。

xchg ax,bx

xchg ax,[0x404020]

【读写IO地址空间】

● in - 读

in al,0x60    ;读取0x60地址中的数据写入al,只能使用al、ax、eax接收数据,分别表示读取1字节、2字节、4字节

in eax,dx     ;可以使用间接寻址,但是只能使用dx寄存器存储IO地址

● out - 写

out 0x60,al

out dx,al

Copyright   2015-2022 东方晨报网 版权所有  备案号:沪ICP备2020036824号-8   联系邮箱:562 66 29@qq.com