在8086CPU中,哪些寄存器可以用"[]"来进行内存单元寻址,并且用该寄存器寻址的段地址是哪一个,都是我们必须明确的.了解汇编只是为了更好的对内存的掌控,更好的编程
一、语法(Syntax)
1.在8086CPU中,只有这四个寄存器(BX,BP,SI,DI)可以用"[]"来进行内存单元寻址。比如下面的指令都是正确的:
mov ax,[bx]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp]
mov ax,[bp+si]
mov ax,[bp+di]
而下面的指令是错误的:
mov ax,[cx]
mov ax,[ax]
mov ax,[dx]
mov ax,[ds]
2.在[]中,这四个寄存器可以当个出现,或只能以四种组合出现:BX和SI、BX和DI、BP和SI、BP和DI,比如下面的指令都是正确的(idata位常量):
mov ax,[bx]
mov ax,[si]
mov ax,[di]
mov ax,[bp]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp+si]
mov ax,[bp+di]
mov ax,[bx+si+idata]
mov ax,[bx+di+idata]
mov ax,[bp+si+idata]
mov ax,[bp+di+idata]
下面的指令是错误的:
mov ax,[bx+bp]
mov ax,[si+di]
3.只要在[]中使用BP,而指令中没有显示地指定段地址,段地址就默认在SS中,比如:
mov ax,[bp];等价于 mov ax,ss:[bp]
二、寻址方式于编译器的应用
下面举两个例子进行实验:
- 用于结构体 [].idata(编译器实现情况有所差异)
- 用于数组 idata[](编译确实这样实现)
关于第一点可能你比较少见(如果你仅仅是学习汇编),下面举一个例子,接下来将进一步叙述:
assume cs:code
data segment
db '123456789'
data ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,0
mov dl,[bx].3
mov ah,2
int 21h
mov ax,4c00h
int 21h
code ends
end start
输出结果为:4
首先,考虑一下一维数组的寻址:
#include "iostream"
using namespace std;
int main()
{
printf("%c\t",3["abcd"]);
system("pause");
return 0;
}
首先我们观察到第一个输出函数,这行语句看起来十分诡异,但是我们知道数组a[3]等价于(a+3),那么同理3[a]是等价于(3+a),这样的话这行代码没什么问题,现在我们来看看这行代码的反编译之后的汇编指令:
010E1916 mov eax,1
010E191B imul ecx,eax,3
010E191E movsx edx,byte ptr string "abcd" (010E7BD8h)[ecx]
010E1925 push edx
010E1926 push offset string "%c\t" (010E7B34h)
010E192B call _printf (010E104Bh)
010E1930 add esp,8
接下来我们反汇编printf("%c\t","abcd"[3]);
01111916 mov eax,1
0111191B imul ecx,eax,3
0111191E movsx edx,byte ptr string "abcd" (01117BD8h)[ecx]
01111925 push edx
01111926 push offset string "%c\t" (01117B34h)
0111192B call _printf (0111104Bh)
01111930 add esp,8
我们可以清楚的发现,第三行的寻址方式并没有发生任何改变,都是idata[]的方式
二维数组的情况将不予赘述,下面考虑结构体的情况:
#include "iostream"
using namespace std;
struct T {
int a;
int b;
};
int main()
{
T *q = new T ;
q->b = 7;
system("pause");
return 0;
}
对q->b = 7;进行反编译得到汇编代码
01271A59 mov eax,dword ptr [q]
01271A5C mov dword ptr [eax+4],7
我们发现寻址方式是dword ptr [eax+4],7,等价于 [eax].4
最后一个有意思的程序,可能是某公司的面试题(面试的时候可能不会给出汇编代码)
#include "iostream"
using namespace std;
struct T {
int a;
int b;
};
int main()
{
T t = { 1,2 };
void *p = &t;
printf("%d",*(int *)&(((char *)p)[(size_t)&(((T*)0)->b)]));
system("pause");
return 0;
}
010E1A46 mov eax,1
010E1A4B shl eax,2
010E1A4E mov ecx,dword ptr [p]
010E1A51 mov edx,dword ptr [ecx+eax]
010E1A54 push edx
010E1A55 push offset string "%d" (010E7C60h)
010E1A5A call _printf (010E1050h)
010E1A5F add esp,8
输出结果:2(注意到第四行汇编[ecx+eax]为成员b的地址)