【问题标题】:Function calling w/ parameters带/参数的函数调用
【发布时间】:2015-10-04 21:59:14
【问题描述】:

我正在努力创建函数并在程序集中调用它们。

函数gfx_draw_h(color, x_1, y_1, x_2) 应该是从(x_1, y_1)(x_2, y_1) 画一条线,但我无法将x_2 的值与gfx_draw_h.repeat 中的当前位置进行比较。

另外,另一段代码是否正确(没有堆栈损坏)?

这是我的代码:

    BITS 16

; ----------------------------------------------------------------------

_start:
    mov ax, 07C0h
    add ax, 288
    mov ss, ax              ; SS = stack space
    mov sp, 4096            ; SP = stack pointer

    mov ax, 07C0h
    mov ds, ax              ; DS = data segment

    call gfx_init

    push 50                 ; x_2
    push 30                 ; y_1
    push 30                 ; x_1
    push 1000b              ; color

    call gfx_draw_h

    add esp, 16

    jmp $                   ; infinite loop

; ----------------------------------------------------------------------
; Initializes graphics.
;
; Sets the video mode.
;
; INPUT:
;   none
;
; OUTPUT:
;   none
;
gfx_init:
    mov ah, 00h             ; set video mode
    mov al, 12h             ; AL = graphical mode
    int 10h                 ; INT 10h / AH = 00h
    ret

; ----------------------------------------------------------------------
; Draws a horizontal line.
;
; INPUT:
;   color
;   x_1
;   y_1
;   x_2
;
; OUTPUT:
;   none
;
gfx_draw_h:
    pop ax                  ; color
    pop cx                  ; x
    pop dx                  ; y

    mov ah, 0Ch             ; change color for a single pixel

.repeat:
    cmp cx, [ebp + 20]      ; !!! THIS IS THE ISSUE !!!
    je  .done

    inc cx
    int 10h

    jmp .repeat

.done:
    ret

; ----------------------------------------------------------------------

times 510 - ($ - $$) db 0   ; padding with 0 at the end
dw 0xAA55                   ; PC boot signature

【问题讨论】:

    标签: assembly x86 x86-16


    【解决方案1】:
    add esp, 16
    

    由于这是 16 位代码,将 4 个参数压入堆栈只需要您弹出 8 个字节。

    gfx_draw_h:
     pop ax                  ; color
     pop cx                  ; x
     pop dx                  ; y
    

    由于 gfx_draw_h 是一个子例程(它是called),因此堆栈上有一个返回地址。你的第一个 pop ax 删除了这个!你可以这样写:

    gfx_draw_h:
     mov bp, sp
     mov ax, [bp+2] ;color
     mov cx, [bp+4] ;x
     mov dx, [bp+6] ;y
    

    按照此逻辑更改问题行,例如(不要使用 EBP!):

    cmp cx, [bp + 8]      ; !!! THIS IS THE ISSUE !!!
    

    【讨论】:

    • 您在用sp 覆盖之前忘记了push bp。现代调试器根本不需要堆栈帧,因此您可以跳过该部分,尤其是。对于不修改 sp 的叶函数。
    • @PeterCordes 我并没有真正忘记push bp,而是试图让它尽可能简单。而且由于 OP 不关心推送任何寄存器...
    • @user3144770 谢谢!我明白我之前做错了什么。 @PeterCordes 我应该push bp 的原因是什么?我在mov bp, sp 之前添加了push bp,在ret 之前添加了pop bp。你说的是这个吗?
    • @user5406450:是的。如果你不保存bp,你会破坏调用者的堆栈帧。 bp 是所有 ABI 中的被调用者保存寄存器:当函数返回时,rbp / ebp / bp 必须具有调用者进行调用时的值。以这种方式使用bp 称为“堆栈帧”。正如我所说,它是可选的。现代 gcc 默认为-fomit-frame-pointer,释放rbp 用作另一个通用寄存器。在堆栈上具有可变长度数组的函数 (int foo[n];) 中,gcc 仍然会创建一个堆栈帧来引用局部变量。 Google 堆栈框架。
    • 恐怕16位寄存器[sp]不是有效的有效地址。我们必须在 16 位代码中使用堆栈帧!
    猜你喜欢
    • 2014-04-02
    • 1970-01-01
    • 2010-11-25
    • 2016-11-13
    • 1970-01-01
    • 2020-07-29
    • 2016-06-17
    • 1970-01-01
    • 2013-02-17
    相关资源
    最近更新 更多