相对寻址方式:对标号地址的另一种相对寻址方式

  汇编中, 对数据访问时, 通常是这样:

_asm{
...
DATA_LABLE:
   _emit 0x87
   _emit 0xa0
   _emit 0x49
   _emit 0x90
...
   mov ebx, dword ptr [DATA_LABLE]
...
}
  其中, 当编译的后, mov指令中DATA_LABLE标号地址会被转成个绝对地址. 而有时绝对地址这点可能会对这样种需求带来障碍: 我们希望自己写汇编代码不管被放在哪块地址空间中都是能正常运行, 就象我们写高级语言中那些样, 位置可以被随意放置, 丝毫不会影响本身功能使用. 当然, 不得不指出是, 尽管要求是同样功能, 但汇编和高级语言的间在这方面实现却相去甚远. 高级语言在最终被编译的后, 其地址也是固定绝对地址, 而我们所想要用汇编实现才是真正"可被任意放置" 2进制执行块.

  借用call指令, 可以实现运行期标号地址相对寻址, 大致思路如下:

_asm{
...
   call FUNC_START
FUNC_START:
   pop ebx
   sub ebx, off FUNC_START
   mov [ebp-xx], ebx
...
DATA_LABLE:
   _emit 0x87
   _emit 0xa0
   _emit 0x49
   _emit 0x90
...
   mov eax, [ebp-xx]
   mov ebx, dword ptr [DATA_LABLE+eax]
...
}
  步骤是这样:

  1.首先, 在汇编功能块或首部, 使用以下语句取得运行期地址和编译地址修正差值.

  call FUNC_START
FUNC_START:
   pop ebx
   sub ebx, off FUNC_START
   mov [ebp-xx], ebx
  略作解释: call 会将eip寄存器压入堆栈, 的后用"pop ebp"是将eip值赋给ebp, 而eip表示是"下条语句地址", 在这里, 当运行到"call FUNC_START"时, 它表示是以标号"FUNC_START:"开始"pop ebx"指令起始地址. 而另方面, sub指令中"off FUNC_START", 在编译时, off会被转成个绝对地址. 这样,通过sub操作, 就获得了此段代码在编译期和运行期有关指令地址修正值. 下面这句: "mov [ebp-xx], ebx", 实际上只是锦上添花, 它把这个值保存在了某个自定义局部变量空间内, 以备后续语句方便引用.

  2.相应, 对标号数据引用就变成这样两句:

  mov eax, [ebp-xx]
   mov ebx, dword ptr [DATA_LABLE+eax]
  对于汇编此类代码进行这样处理后, 此段 2进制执行块就可以被放置在任意地方而不致对DATA_LABLE数据地址引用造成.

Tags:  8086寻址方式 什么是寻址方式 寻址方式 相对寻址方式

延伸阅读

最新评论

发表评论