在装配中按值传递和按引用传递 [英] Pass by value and pass by reference in Assembly

查看:89
本文介绍了在装配中按值传递和按引用传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解决这个问题:

创建一个 PROC 过程,该过程将一个参数作为按值传递,并根据作为参数传递的数字打印出"X"的数字. 在打印之前,请确保参数为正数,在程序结束时,您需要将已使用的寄存器改回其第一个值.

如果该过程的输入为5,则控制台上的输出应为:

XXXXX

这是我的代码:

var db 5 ;In the dataseg  
push [var] ;in the codeseg  

proc example  
    pop cx  
    cmp cx,0  
    ja print  
print:  
    mov dl, 'X'  
    mov ah, 2h  
    int 21h  
    loop print  
    ret  
endp example  

该代码将按预期工作,如果不能,为什么?怎么解决?

解决方案

不,您的代码已严重损坏.

函数使用mov ecx, [esp+4]之类的东西从堆栈访问其args.或在16位代码中,[sp+2]不是可编码的寻址模式,因此您应制作一个堆栈帧:
push bp/mov bp, sp/mov cx, [bp+4]. (然后在函数末尾撤消此操作). Google提供了有关堆栈框架"的更多信息,以及x86函数如何在堆栈上访问其args. (或参见标签wiki的问题).

这是假设您需要在堆栈上传递args.一些调用约定将前两个args传递给寄存器,从而节省了指令esp.小型功能.


您的函数以ret结尾,这意味着您假设使用call进行了调用.返回地址将位于函数条目上的[sp](或32位代码中的[esp])上.此时的pop将加载返回地址.如果在返回地址低于sp时发​​生中断,它将被覆盖,因此pop是不安全的,然后在ret之前再次将sp调低.

按一个arg然后进入一个函数不是一个好习惯.


您的分支也是错误的:

    cmp cx, 0
    ja print  
print:         ; execution ends up here whether the branch is taken or not

使用ja意味着您将arg视为未签名.很好,因为它仍然有可能为零而变为非正数.但是,我认为任务是打算让您将arg视为已签名.尝试使用jle nonpositive之类的东西,然后将nonpositive:放在有用的地方.


标签Wiki的问题具有指向以下内容的链接教程和参考资料.有了+调试器+ google,您应该就能回答自己的问题.

I'm trying to solve this problem:

Create a PROC procedure that takes one parameter as Pass by Value and prints the number of 'X' according to the number passed as a parameter. Before printing, make sure parameter is a positive number, at end of program you need to change the registers that have been used back to their first values.

If the input to the procedure is 5 then the output on the console should be:

XXXXX

This is my code:

var db 5 ;In the dataseg  
push [var] ;in the codeseg  

proc example  
    pop cx  
    cmp cx,0  
    ja print  
print:  
    mov dl, 'X'  
    mov ah, 2h  
    int 21h  
    loop print  
    ret  
endp example  

Will this code work as expected, and if not, why? How can it be fixed?

解决方案

Nope, your code is seriously broken.

Functions access their args from the stack with stuff like mov ecx, [esp+4]. Or in 16bit code, [sp+2] isn't an encodable addressing mode, so you should make a stack frame:
push bp / mov bp, sp / mov cx, [bp+4]. (And undo this at the end of the function). Google "stack frame" for more about this, and how x86 functions access their args on the stack. (Or see the tag wiki).

This is assuming you need to pass args on the stack. Some calling conventions pass the first couple args in registers, which saves instructions esp. in small functions.


Your function ends with ret, which means you're assuming you were called with a call. The return address will be at [sp] (or [esp] in 32bit code) on function entry. A pop at that point will load the return address. If an interrupt comes in while the return address is below sp, it will be overwritten, so it's not safe to pop and then adjust sp back down again before ret.

Pushing an arg and then falling through into a function is not good practice.


Your branch is also wrong:

    cmp cx, 0
    ja print  
print:         ; execution ends up here whether the branch is taken or not

Using ja means you're treating your arg as unsigned. That's fine, since it's still possible for it to be non-positive by being zero. However, I think the assignment was intending you to treat the arg as signed. Try something like jle nonpositive, and put nonpositive: somewhere useful.


The tag wiki has some links to tutorials and reference material. With that + a debugger + google, you should be able to answer your own questions.

这篇关于在装配中按值传递和按引用传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆