我无法理解堆栈是如何工作的。我很困惑我读过但我的思绪无法得到它。它与bit有关。我不确定我是否正确,但是在堆栈中"职位"是2和2,因为它是2 * 8bits所以它[6]采取第三个元素?我不确定你是否能解释我这部分代码我会很高兴。
SUM_PIN PROC NEAR ;it starts the routine
V1: MOV BP,SP ;SP moves to BP.As far as i remember BP is down on stack
V2: MOV AX,0 ;AX takes the 0
V3: MOV BX,[BP+6] ;it has something to do with 2 bit but i didn't catch it
V4: MOV CX,[BP+4]
V5: MOV DL,[BX]
V6: MOV DH,0
ADD AX,DX
V7: INC BX ;increase BX
V8: LOOP V5 ;go back at V5
v9: MOV BX,[BP+2]
v10:MOV [BX],AX
V11:RET ; return
SUM_PIN ENDP ;end
答案 0 :(得分:0)
"堆"是普通的计算机内存,使其成为堆栈"按使用方式。在x86-16" 16位实模式下#34;当前"堆栈顶部"是地址ss:sp
。与ss=0x1234:sp=0x5678
类似,意味着物理内存地址0x179B8
被称为"堆栈顶部"。
如果你做call near SUM_PIN
,call
之后的下一条指令的16位偏移量被存储到堆栈中(如push offset <return_address>
),即从{{1}中减去2 }} =&gt; sp
,并且该内存设置为包含返回地址偏移量(即16位,因此将使用sp=0x5676
和1234:5676
个内存单元格。
现在在1234:5677
内,SUM_PIN
设置为bp
,因此它将寻址相同的内存(sp
指向该返回地址)。 ss:bp
超出此范围,因此无论调用bp+2
子例程,它都应该将参数数据放入堆栈内存。
从代码用法中可以调用它,例如:
SUM_PIN
在push offset <some_unsigned_byte_array_label>
push <length_of_array>
push offset <some_label_to_spare_word_memory_to_store_result>
call SUM_PIN
; read result of the subroutine from memory into ax
mov ax, [some_label_to_spare_word_memory_to_store_result]
内,SUM_PIN
将达到上一个ss:bp+2
的值(内存地址的偏移量,应该写入结果),push
将达到第二次推送存储数组中元素的数量,ss:bp+4
将达到第一次推送,这是要求求和的某个数组的地址的偏移量。
确保您了解在哪种情况下使用默认段寄存器,当使用ss:bp+6
寻址时,默认段寄存器为[bp+displacement]
,因此像ss
这样的指令将获取内容mov cx,[bp+4]
段中的内存,但ss
使用mov dl,[bx]
作为基址寄存器具有默认段bx
,因此它将使用当前{{1}扩展堆栈的偏移量提取} value来计算物理内存地址。
堆栈内存没有什么特别之处,除了你有许多隐含操作的指令(ds
),而在16位实模式中,&#34; OS&#34; (中断)与用户app共享堆栈,所以ds
以下的值被定时器/键盘/中断每秒覆盖几次...中断存储返回地址和保留的寄存器值,即你不能使用存储器可靠地存储您的值。
覆盖/ push, pop, call, ret, enter, leave, pushf, popf, ...
以上的值将覆盖当前堆栈中的值,因此这不是存储值的完美位置。但是如果你第一次&#34;保留&#34;通过执行ss:sp
之类的操作,您可以安全地使用该空间ss:sp
(现在中断将其值存储在当前sub sp,40
之下),然后&#34;发布&#34;恢复sp+0 .. sp+39
,例如sp
。
总的来说,您应该使用一些调试器(emu8086有一个),在sp
区域打开内存视图,并使用add sp,40
指令查看内存中的值是如何演变的,以及{{1}通过其他指令在该区域上/下移动。
答案 1 :(得分:-1)
自从我组装以来已经过了很长时间,这是x86的味道......但是我会尝试引导你完成这个(通过一些猜测)
SUM_PIN PROC NEAR ;it starts the routine
V1: MOV BP,SP ;SP moves to BP.As far as i remember BP is down on stack
这会加载BP寄存器中的堆栈指针值
V2: MOV AX,0 ;AX takes the 0
AX = 0
V3: MOV BX,[BP+6] ;it has something to do with 2 bit but i didn't catch it
加载BX的值比BP指向的值高6个字节。由于自MOV BP,SP&#39以来BP未被修改,因此与当前堆栈位置之上的六个字节相同&#34;
V4: MOV CX,[BP+4]
使用高于堆栈底部四个字节的值加载CX。 &#34; LOOP&#34;命令将自动递减该值,并且将通过&#34;当CX达到0时
V5: MOV DL,[BX]
使用BX指向的地址中的值加载DL
V6: MOV DH,0
ADD AX,DX
AX = AX + DL
V7: INC BX ;increase BX
向BX添加一个(移动到BX指向的下一个字节)
V8: LOOP V5 ;go back at V5
v9: MOV BX,[BP+2]
使用最后一个参数的值将BX加载到函数中(BP == SP ==堆栈底部==地址,以便在调用RET时返回)
v10:MOV [BX],AX
将AX存储在BX指向的地址
V11:RET ; return
SUM_PIN ENDP ;end
理解这一点的关键是堆栈增长 DOWNWARD 。因此,如果将两个字节的值压入堆栈,SP = SP - 2
知道并阅读此代码,我可以看出[BP + 4]是一个2字节的值。我猜测[BP + 6]是一个指向字节数组的指针。
这个的C / C ++签名可以读作(类似):
void SUM_PIN(byte* first, int someValueThatIsNotUsed, int *total)
所以我猜C / C ++版本会是这样的:
void SUM_PIN(byte* first, int count, int *total) {
int A = 0;
byte *b = first;
while (count-- > 0) {
a = a + *b
b = b + 1
}
return a
}
编辑:基于评论,CX自动被评估为AL&#34; flavor&#34;的特征。我忘记了或者没有意识到。我修改了我的for循环来反映