assembly - 汇编中按值传递和按引用传递

标签 assembly parameters dos masm x86-16

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

创建一个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  

这段代码会按预期工作吗?如果没有,为什么?如何解决?

最佳答案

作为 Peter 答案的附录,您可以使用 MASM/TASM 生成序言和尾声代码来为您设置BP,并允许您通过标签访问过程/函数参数。关于 MASM 和 TASM 使用的 PROC 子例程的相当好的教程可以在 here 找到。

我还将 var 更改为 WORD 而不是 BYTE。生成的代码如下所示:

.MODEL SMALL
.STACK 100H

.DATA
    var dw 5           ; Change to 16-bit WORD

.CODE

example proc C         ; C Calling convention - parameters on stack right to left
    ARG num:WORD       ; We take one argument called `num` that is a word

    mov cx, num        ; Move the 16-bit value in `num` to CX counter
                       ;     same as: mov cx, [bp+4]
                       ;     [bp+0] is saved copy of BP put on stack by MASM's prologue
                       ;     [bp+2] return address placed on stack by CALL
    cmp cx, 0
    jle negative       ; If we are less than or equal to 0, exit procedure
    mov dl, 'X'
    mov ah, 2h         ; ah and dl not destroyed by int 21h/ah=2 so set them once
                       ;     before loop
print:
    int 21h            ; Print an 'X'
    loop print         ; Continue until loop is 0
negative:
    ret
endp example

main proc
     mov ax, @data     ; initialize DS
     mov ds, ax

     push [var]        ; Push 2-byte value at `var` (pushing by value)
     call example
     add sp, 2         ; Remove parameter from stack
                       ;     Not necessary since we use int 21h to exit right after
     mov ah, 4ch       ; return control to DOS
     int 21h
main endp

end main               ; Entry point = label main

上面的代码将为过程示例生成这些指令:

example proc
    push bp            ; Save BP on stack  \
    mov bp, sp         ; Set BP to SP      / Function prologue
                       ;     [bp+0] is saved copy of BP put on stack by prologue
                       ;     [bp+2] return address placed on stack by CALL
                       ;     [bp+4] first parameter (NUM)

    mov cx, [bp+4]     ; Move the value at BP+4 (NUM) to CX counter

    cmp cx, 0
    jle negative       ; If we are less than or equal to 0, exit procedure
    mov dl, 'X'
    mov ah, 2h         ; ah and dl not destroyed by int 21h/ah=2 so set them once
                       ;     before loop
print:
    int 21h            ; Print an 'X'
    loop print         ; Continue until loop is 0
negative:
    mov sp, bp         ; Restore stack pointer \
    pop bp             ; Restore BP register   / Function epilogue
    ret
endp example

我将其作为练习留给读者,以确定示例PROC更改的所有寄存器,并根据作业中的要求保存/恢复它们。提示:在ARG指令之后PUSH它们,并在RET之前以相反的顺序POP它们

关于assembly - 汇编中按值传递和按引用传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36293714/

相关文章:

assembly - 为什么我们必须在MS-DOS 中初始化DS 和ES 寄存器?

batch-file - for 循环中的多个 do 命令 : Echoing a string to a file and then redirecting to the command window

汇编语言随机数生成器

c - 寄存器如何作为汇编中的参数工作?

c++ - 如何编写带有 'asm volatile'的btr指令

c - intel x86 - 为什么 -4(%ebp) 没有任何意义?

reporting-services - 使用 ODBC 连接到 SQL SERVER 时,SSRS 错误必须声明标量变量

类型为 "void(*)(int wall) is incompatible with parameter of type "int 的 C++ 参数”

java - 如何将子类参数传递给父类(super class)私有(private)变量?

程序集 - 程序按预期工作,但第二次运行时,打印出乱码