📄 汇01.txt
字号:
mov edx,04 ;访问i_array[1][1],编译时就已经确定
mov word ptr [ebx+edx*2], 16 ;
当然,取决于不同的编译器和程序上下文,具体实现可能不同,但这种基本的形式是确定的。从这里也可以看到比例因子的作用(还记得比例因子
的取值为1,2,4或8吗?),因为在目前的系统中简单变量总是占据1,2,4或者8个字节的长度,所以比例因子的存在为在内存中的查表操作提供了
极大方便。
4. 结构和对象
结构和对象的成员在内存中也都连续存放,但有时为了在字边界或双字边界对齐,可能有些微调整,所以要确定对象的大小应该用sizeof操作符而
不应该把成员的大小相加来计算。当我们声明一个结构变量或初始化一个对象时,这个结构变量和对象的名字也对应一个内存地址。举例说明:
struct tag_info_struct
{
int age;
int sex;
float height;
float weight;
} marry;
变量marry就对应一个内存地址。在这个地址开始,有足够多的字节(sizeof(marry))容纳所有的成员。每一个成员则对应一个相对于这个地址的偏
移量。这里假设此结构中所有的成员都连续存放,则age的相对地址为0,sex为2, height 为4,weight为8。
; marry.sex=0;
lea ebx,xxxxxxxx ;marry 对应的内存地址
mov word ptr [ebx+2], 0
......
对象的情况基本相同。注意成员函数具体的实现在代码段中,在对象中存放的是一个指向该函数的指针。
5. 函数调用
一个函数在被定义时,也确定一个内存地址对应于函数名字。如:
long comb(int m, int n)
{
long temp;
.....
return temp;
}
这样,函数comb就对应一个内存地址。对它的调用表现为:
CALL xxxxxxxx ;comb对应的地址。这个函数需要两个整型参数,就通过堆栈来传递:
;lresult=comb(2,3);
push 3
push 2
call xxxxxxxx
mov dword ptr [yyyyyyyy], eax ;yyyyyyyy是长整型变量lresult的地址
这里请注意两点。第一,在C语言中,参数的压栈顺序是和参数顺序相反的,即后面的参数先压栈,所以先执行push 3. 第二,在我们讨论的32位系
统中,如果不指明参数类型,缺省的情况就是压入32位双字。因此,两个push指令总共压入了两个双字,即8个字节的数据。然后执行call指令。
call 指令又把返回地址,即下一条指令(mov dword ptr....)的32位地址压入,然后跳转到xxxxxxxx去执行。
在comb子程序入口处(xxxxxxxx),堆栈的状态是这样的:
03000000 (请回忆small endian 格式)
02000000
yyyyyyyy <--ESP 指向返回地址
前面讲过,子程序的标准起始代码是这样的:
push ebp ;保存原先的ebp
mov ebp, esp;建立框架指针
sub esp, XXX;给临时变量预留空间
.....
执行push ebp之后,堆栈如下:
03000000
02000000
yyyyyyyy
old ebp <---- esp 指向原来的ebp
执行mov ebp,esp之后,ebp 和esp 都指向原来的ebp. 然后sub esp, xxx 给临时变量留空间。这里,只有一个临时变量temp,是一个长整数,需要4
个字节,所以xxx=4。这样就建立了这个子程序的框架:
03000000
02000000
yyyyyyyy
old ebp <---- 当前ebp指向这里
temp
所以子程序可以用[ebp+8]取得第一参数(m),用[ebp+C]来取得第二参数(n),以此类推。临时变量则都在ebp下面,如这里的temp就对应于[ebp-4].
子程序执行到最后,要返回temp的值:
mov eax,[ebp-04]
然后执行相反的操作以撤销框架:
mov esp,ebp ;这时esp 和ebp都指向old ebp,临时变量已经被撤销
pop ebp ;撤销框架指针,恢复原ebp.
这是esp指向返回地址。紧接的retn指令返回主程序:
retn 4
该指令从堆栈弹出返回地址装入EIP,从而返回到主程序去执行call后面的指令。同时调整esp(esp=esp+4*2),从而撤销参数,使堆栈恢复到调用子程
序以前的状态,这就是堆栈的平衡。调用子程序前后总是应该维持堆栈的平衡。从这里也可以看到,临时变量temp已经随着子程序的返回而消失,
所以试图返回一个指向临时变量的指针是非法的。
为了更好地支持高级语言,INTEL还提供了指令Enter 和Leave 来自动完成框架的建立和撤销。Enter 接受两个操作数,第一个指明给临时变量预留
的字节数,第二个是子程序嵌套调用层数,一般都为0。enter xxx,0 相当于:
push ebp
mov ebp,esp
sub esp,xxx
leave 则相当于:
mov esp,ebp
pop ebp
=============================================================
好啦,我的学习心得讲完了,谢谢各位的抬举。教程是不敢当的,因为我也是个大菜鸟。如果这些东东能使你们的学习轻松一些,进步快一些,本
菜鸟就很开心了。
====================================================
举例说明在汇编语言中,"[]"的用法
作者:FTBirthday 来源:看雪论坛 加入时间:2003-6-4
"[]"的用法在"常见问题"已经有所说明,引用如下:
1、push dword ptr [024c1100] 压栈024c1100值的双字
2、cmp eax,[ebp+14] eax-ebp+14的有效值,不保留值,主要看标志位
3、cmp byte ptr [eax],46 字节型eax-46,看标志位
4、lea eax,[edx-02] 把edx-02的有效值(一个地址值)给eax
5、mov ecx,[edx+08] edx+8值作为地址,此地址所指向的值给ecx
我再补充几例我遇到的情况,参考了一些资料,以及我个人的理解.
-------------------------------------------------------------------------------
mov指令中用到"[]"
1--mov [edi], eax ----把eax的值(dword)赋给位于内存地址edi处的值
2--mov [bp-02], dx ---把dx的值(word)赋给位于内存地址bp-02处的值
3--mov esi,[BP+14] ---把位于内存地址BP+14的dword大小的值移入esi寄存器
4--mov eax, dword ptr [ebp-04]---把位于内存地址ebp-04的dword大小的值移入eax寄存器
5--mov eax, dword ptr[0000003Ah]--把位于内存地址3A的dword大小的值放入eax寄存器
6--mov cl, byte ptr [34h]--把位于内存地址34的byte大小的值放入cl寄存器
7--mov dx, word ptr [3Eh]--把位于内存地址3E的word大小的值放入dx寄存器
8--mov eax,[00403045h] --从内存地址403045读取一个32位的值
9--mov al, byte ptr [eax+ecx]--把位于内存地址eax+ecx的byte大小的值放入al寄存器
综括号"[]"用来从括号间的内存地址处取值,没有括号就只是这个值,寄存器和内存地址也可以.
10--mov cx,[eax]--把位于内存地址eax的word大小的值移入cx寄存器
在mov cx, [eax]中,处理器会先查看eax装有什么值(=内存地址),然后在那个内存地址中有什么值,并把这个word(16位,因为目标-cx-是个16位寄
存器)移入cx。
-------------------------------------------------------------------------------
cmp指令中用到"[]"
1--cmp dword ptr [ebp-04], 00000007--把位于内存地址ebp-04的dword大小的值与00000007比较
2--cmp byte ptr [si], 00 --把位于内存地址si的byte大小的值与00比较
-------------------------------------------------------------------------------
lea指令中用到"[]"
1--lea di, [bp-22] ----把bp-22的有效值(=内存地址)给di
-------------------------------------------------------------------------------
test指令中用到"[]"
1--test byte ptr [bx+08FD]
--将位于内存地址bx+08FD处的byte大小的值逻辑与,判断运算结果是否为00
理解上难免有偏差,请指正!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -