0

我有这样的变量:

myVar db 'A','B',0

我需要在屏幕上打印的字符串中间嵌入“A”和“B”。像这样的东西:

CALL PTHIS
db 'first val is ', %1, ' second val is ', %2, 0

我想我在某个地方看到过类似的东西。如何才能做到这一点?

4

1 回答 1

1

为了回答,我写了一个非常简单的 printf 解析器。它像 C 的老大哥一样工作,但只理解格式说明符 '%c' 和 '%s'。这也可以扩展。

这也是探索C 调用约定的一个很好的例子。

以下程序在 EMU8086、TASM、JWASM 和 MASM>=6.0 中汇编:

.MODEL tiny                     ; For MASM 6 and TASM
.CODE                           ; For MASM 6 and TASM
.186                            ; For MASM 6 (push immediates)
ORG 100h                        ; Origin for COM program


start:
                                ; printf (&format, &myVar, myVar[0], myVar[1])
    push WORD PTR myVar + 1     ; Forth argument (single character directly pushed)
    push WORD PTR myVar + 0     ; Third argument (single character directly pushed)
    push OFFSET myVar           ; Second argument (address of null terminated string)
    push OFFSET fmt             ; First argument (address of null terminated format string)
    call printf
    add sp, 2 * 4               ; Adjust stack: 4 arguments a 2 bytes

    lea dx, report
    mov ah, 09h
    int 21h

    RET                         ; return to operating system.


printf PROC
        push bp                 ; Prologue
        mov bp, sp
        sub sp, 2 * 3           ; Reserve local stack for three WORDs
        mov [bp-2], bx          ; Preserve BX (CCall calling convention)
        mov [bp-4], si          ; Preserve SI (CCall calling convention)
        mov [bp-6], di          ; Preserve DI (CCall calling convention)

        mov di, 4               ; Counter to the arguments
        mov si, [bp+di]         ; Get the first argument
    output:
        mov ax, [si]            ; Get two characters
        cmp al, '%'             ; First charcter == '%'
        jnz J1                  ; No, skip over the placeholder blocks

        cmp ah, 'c'             ; Second character == 'c'
        jnz no_c                ; No, skip over the '%c' placeholder block
        inc si                  ; Adjust the index to format string
        add di, 2               ; Point to the next argument on stack
        mov al, BYTE PTR [bp+di]    ; Get the argument (it is a directly pushed character)
        jmp J1                      ; and print it
    no_c:

        cmp ah, 's'             ; Second character = 's'
        jnz no_s                ; No skip over the %s placeholder block
        add si, 2               ; Adjust the index to format string
        add di, 2               ; Point to the next argument on stack
        mov bx, [bp+di]         ; Get argument (it is an offset to an ASCIIZ string)
    next:
        mov al, [bx]            ; Get character
        test al, al             ; character == 0
        jz output               ; Yes - this string is ready, turn back to format string
        mov ah, 0Eh             ; Teletype
        int 10h                 ; BIOS
        inc bx                  ; Point to next charcter
        jmp next                ; Repeat the output
    no_s:

    J1:
        test al, al             ; Character == 0?
        jz ready                ; Yes, format string is ready, print is done

    doit:
        mov ah, 0Eh             ; Teletype
        int 10h                 ; BIOS
        inc si                  ; Point to next character
        jmp output              ; Repeat the bunch

    ready:
        mov bx, [bp-2]          ; Restore BX (CCall calling convention)
        mov si, [bp-4]          ; Restore SI (CCall calling convention)
        mov di, [bp-6]          ; Restore DI (CCall calling convention)
        mov sp, bp              ; Epilogue
        pop bp
        ret
printf ENDP

fmt     db "From the word %s is the first char %c and the second char %c",0
myVar   db 'H','e','l','l','o',0
report  db 13,10,13,10,"I'm back to the root",13, 10,'$'

END start                       ; Directive to stop the compiler.
于 2020-01-27T13:11:32.903 回答