Ian*_*one 0 c assembly tasm turbo-c++ x86-16
我要进行汇编测试,并且对汇编指针有疑问。我正在尝试锻炼,但无法解决。
考虑一下C中的语句:
int x=100, y=200;
int far *ptx;
int far *pty;
Run Code Online (Sandbox Code Playgroud)
假设指令已经执行:
ptx=&x;
pty=(int *)malloc(sizeof(int));
Run Code Online (Sandbox Code Playgroud)
我的问题是关于如何在汇编中编码以下几点:
ptx=pty*ptx=*pty这些声明是否应该在全球范围内使用?如果是这样,则在静态存储中将为C变量提供asm标签。如果不是(函数内的局部变量),则它们将位于堆栈中,并且IDK将如何期望您知道它们与BP的偏移量。
无论哪种方式,它们都是32位seg:off(小尾数,因此在低16位偏移)远指针,因此将一个副本复制到另一个副本仅是4字节副本,您可以使用2个整数加载+存储。
指针变量(当它们不优化或不优化时)将指针值本身存储在内存中,就像intor一样long。在C中,当您这样做时*pty,编译器必须将指针值加载到寄存器中,然后再次加载指向的内存。
我将假设它DS指向指针值本身存储在内存中的数据段。sizeof(int)=2之所以这样,是因为对于16位C实现而言,这似乎很有可能。
要取消引用并加载指向的内存pty,即*pty,您需要将部分指针的段部分加载到段寄存器中,将偏移量部分加载到SI,DI或BX(可用作寄存器的一部分)中。寻址模式)。x86对此有说明,例如les/lds。
由于我们可能不想修改DS,我只用ES。(不同的汇编器对段覆盖使用不同的语法,例如[es: di]对于NASM,但我认为可能是es:[di]对于TASM。)
;; *ptx = *pty
;; clobbers: ES, DI, and AX
; load *pty
les di, [pty] ; load pty from [DS:pty] into ES:DI
mov ax, es:[di] ; load *pty into AX
; store *ptx
les di, [ptx] ; load ptx from [DS:ptx] into ES:DI
stosw ; store to *ptx from AX
Run Code Online (Sandbox Code Playgroud)
STOSW将AX存储到ES:DI,并根据方向标志DF递增或递减DI。在执行此指令后,我们并不关心DI的值,但是Turbo C ++的标准调用约定(和现代的x86约定DF=0)在函数进入/退出时表示(向上递增)。
mov如果您尚未了解字符串指令,请在其他段替代中使用plain 。
(@MichaelPetch说,DS通常在16位实模式调用约定中保留呼叫,但是ES 可以随意保存而不用保存/恢复它,因此显然我猜对了。)
或者,如果您可以破坏DS和ES,则可以使用MOVSW。使用push / pop ds来保存/恢复将是更多说明。(但代码大小仍然较小)
;; assuming DS is correct for referencing static data like [pty]
les di, [pty] ; load pty from [DS:pty] into ES:DI
lds si, [ptx] ; load ptx from [DS:ptx] into DS:SI
movsw ; copy a word from [DS:SI] to [ES:DI]
Run Code Online (Sandbox Code Playgroud)
请注意,我使用了ldssecond,因为我假设静态存储中的两个全局变量都可以通过的传入值进行访问DS,而不管其他远指针的一部分是什么段值。
如果您有一个“巨大的”或“巨大的”内存模型(或并非所有静态数据都可以容纳在一个64k段中的其他模型),这将更加复杂,但是您的问题没有显示任何有关何处ptx和何处pty的信息实际存储。
另外,我假设您不应该根据最近分配的方式来优化它们,即使问题向您显示了它们的指向。
如果您知道ptx = &x,则无需ptx从内存中加载,只需mov [x], ax(再次假设x通过DS可以访问静态数据之类的代码模型)。
另外,*pty当它指向新malloc存储时,读起来几乎没有意义,因为这是未初始化的。另一种方式是有道理的。我可能过度分析了。