1.用C语言实现内存写入(harib01a)
章节开始展示了一个用于写入内存的汇编函数: _write_mem8
对于注释: [ESP + 4]存放的是地址解释:
函数调用的时候参数的压栈顺序是从右到左的,因此有如下结构:
- 初始情况假设栈底位置为0x1008,(SS不重要,这里只是做出了标注,并没有给出数值),那么SP寄存器的值应该是栈的最高地址 + 1,0x1008 + 1 = 0x1009,如图
-
栈压入一个参数,如果有汇编基础这块应该好理解,没有也没关系,这里给出压栈CPU执行的指令:
其实很简单,首先SP指针往“上”移动参数大小(字节)个位置,在这里因为用的是ESP,32位拓展寄存器,因此操作的单位数为4字节,也就是SP = SP - 4,然后再将参数data写入到栈中,如图:
-
压入第二个参数 addr,与第个二步骤一样:
-
压入返回地址:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行
更多有关函数调用时如何压栈请点击:函数调用过程中栈到底是怎么压入和弹出的?
到此,就能够理解为什么第一个参数存放的位置是 [ESP + 4] 了吧,跟栈的特点有关(栈从高地址向低地址压入元素)以及push指令的执行。
依次类推,要访问data参数,那么需要偏移2 * 4 = 8:[ESP + 8]
函数类似于C语言中的"write_mem8(0x1234, 0x56);“语句,执行动作相当于"MOV BYTE[0x1234], 0x56”,也就是将数值0x56写入到0x1234内存字节单元中。
想要取得用参数指定的数值0x1234或0x56的内容,就用MOV读入寄存器。因为CPU已经是32位模式,所以我们积极用32位寄存器,16位寄存器也可以使用, 不过机器语言的字节数会增加,执行速度也会变慢。
在指定内存的时候,如果使用16位寄存器:[CX] 或 [SP] 之类的就会出错,但使用32位寄存器,类似:[ECX]、[ESP]都没问题。
需要注意:如果与C语言联合使用,有的寄存器可以自由使用,有的寄存器不能随便使用,能自由使用的只有 EAX、ECX、EDX 这三个,至于其他寄存器,只能使用其值,而不能改变其值,因为这些寄存器在C语言编译后后生成的机器语言中,用于记忆非常重要的值。因此这次我们只用EAX和ECX。
如下图,作者还在naskfunc.nas增加了这条语句(描黑部分):