我有这样的变量:
myVar db 'A','B',0
我需要在屏幕上打印的字符串中间嵌入“A”和“B”。像这样的东西:
CALL PTHIS
db 'first val is ', %1, ' second val is ', %2, 0
我想我在某个地方看到过类似的东西。如何才能做到这一点?
为了回答,我写了一个非常简单的 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.