MASM中通过引用传递参数时获取错误值的问题排查
MASM中值传递与引用传递的差异问题
我正在学习MASM中按引用传递并访问值的方法,先写了一个使用Irvine.inc库的简单程序,用来显示val1和val2的值:
INCLUDE Irvine32.inc .386 .model flat, stdcall .stack 4096 ExitProcess PROTO, dwExitCall: DWORD .data ;date values array DWORD 100, 100, 200 val1 DWORD 50 val2 DWORD 6000 charVal BYTE 'x', 0 .code ;Code main PROC mov eax, val1 ;this is a test to see if it works properly. call WriteDec ;writes eax in Decimal form to the console push OFFSET val1 ;push two values by reference onto the stack push OFFSET val2 call PrintNum INVOKE ExitProcess, 0 main ENDP PrintNum PROC push ebp ;save ebp so we can go back to the program mov ebp, esp ;esp should point to the top of the stack pushad ;why do we need to do this? mov eax, 0 ;zero out eax because I though that might be the problem mov eax, [ebp+12] ;this should move what is in the value of ebp+12 into eax (val1) call WriteDec ;this writes what is in eax to the console mov eax, [ebp+8] ;this should move what is in the value of ebp+8 into eax (val2) call WriteDec ;this writes what is in eax to the console pop ebp ;get back to correct ebp section of the code popad ;needed to do this because pushad from before ret PrintNum ENDP End main
这个程序运行后无法正确输出地址中的值,后来按照@Jester的建议添加mov eax, [eax]后,程序能够正常运行。但随后我编写了另一个测试程序,未添加该指令却也能正常运行:
.386 .model flat, stdcall .stack 4096 ExitProcess PROTO, dwExitCall: DWORD .data ;date values val1 DWORD 200 val2 DWORD 100 .code ;Code main PROC push val1 ;needed to add the offset not the value push val2 ;needed to add the offset not the value call PrintVars INVOKE ExitProcess, 0 main ENDP PrintVars PROC push ebp mov ebp, esp mov eax, [ebp+12] ;mov address of val1 into eax ;mov eax, [eax] ;use address to get actual value call WriteDec ;write the dec to the console call Crlf ;carage return mov eax, [ebp+8] ;mov address of val2 into eax ;mov eax, [eax] ;deference address to actual value call WriteDec ;write the dec to console call Crlf ;carage return pop ebp ret PrintVars ENDP End main
想请教这两个程序之间的差异是什么?
核心差异:传递的是「变量值」还是「内存地址」
第一个程序:按引用传递(传递地址)
你在main中使用push OFFSET val1/push OFFSET val2,压入栈的是val1和val2的内存地址(而非变量本身的数值)。因此在PrintNum中,[ebp+12]和[ebp+8]读取到的是地址值,直接用WriteDec输出的是地址的十进制数值,不是变量的值。必须通过mov eax, [eax]完成解引用,从地址指向的内存中取出实际变量值,才能正确输出。第二个程序:按值传递(传递变量值)
你在main中使用push val1/push val2,压入栈的是val1和val2的实际数值(而非地址)。因此在PrintVars中,[ebp+12]和[ebp+8]直接读取到的就是变量的数值,无需额外解引用,WriteDec可以直接输出正确结果。
另外补充第一个程序的小问题:PrintNum中pop ebp和popad的顺序错误——栈是后进先出结构,你先执行了pushad再push ebp,所以出栈时应该先执行popad恢复寄存器,再执行pop ebp恢复基址指针,否则会导致寄存器状态混乱。
内容的提问来源于stack exchange,提问作者Funlamb
相关产品推荐
相关产品推荐

