[英]Writing to stderr in x86 assembly
我對匯編很新,我想知道如何將輸出寫入stderr。 我知道您可以訪問C標准庫函數,如printf,以打印到控制台。 但我無法弄清楚如何打印到stderr。 我試圖使用fprintf,但我只是猜測參數,我不知道如何指定stderr作為文件指針。 謝謝。
編輯:根據sehe的建議,我嘗試了這個:
.586
.model small,c
.stack 100h
.data
msg db 'test', 0Ah
.code
includelib MSVCRT
extrn fprintf:near
extrn exit:near
public main
main proc
push offset msg
push 2 ;specify stderr
call fprintf ;print to stderr
push 0
call exit ;exit status code 0
main endp
end main
但它只是導致我的程序崩潰。 還有其他建議嗎?
你在使用MSVCRT DLL的fprintf嗎?
第一個參數是指向流的指針。 以下是如何在匯編中使用fprintf。 此外,從Assembly調用C函數時,需要在每次調用參數后調整堆棧。
另外,BIGGIE ......你的字符串是NOT NULL終止的! 您必須NULL終止字符串,這是函數查找字符串長度的方式。 不確定你正在使用什么匯編程序,但這是你在MASM中可以做到的:
include masm32rt.inc
_iobuf STRUCT
_ptr DWORD ?
_cnt DWORD ?
_base DWORD ?
_flag DWORD ?
_file DWORD ?
_charbuf DWORD ?
_bufsiz DWORD ?
_tmpfname DWORD ?
_iobuf ENDS
FILE TYPEDEF _iobuf
.data
msg db 'test', 0Ah, 0
.data?
stdin dd ?
stdout dd ?
stderr dd ?
.code
start:
call crt___p__iob
mov stdin,eax
add eax,SIZEOF(FILE)
mov stdout,eax
add eax,SIZEOF(FILE)
mov stderr,eax
push offset msg
push eax
call crt_fprintf
add esp, 4 * 2
push 0
call crt_exit
end start
我來到這里是因為我在Debian Linux下寫stderr時遇到了麻煩。 我使用yasm,因為我正在閱讀Ray Seyfarth的書。 我正在編寫Intel語法和匯編elf64格式和dwarf2調試協議。
我第一次嘗試使用fprintf遇到了分段錯誤。 我看着stdio的內部。 我設法編寫了相當於一行的程序:
int main()
{
fprintf(stderr, "%d\n", 3);
}
但是當我完全修改它時,我又開始遇到分段錯誤。 我的目標是讓裝配相當於:
int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s n\n", argv[0]);
} else {
/* program code */
}
}
我的最終解決方案是使用sprintf()調用,然后使用文件描述符進行write()系統調用。 還需要調用strlen()。 此策略應該適用於可以從匯編代碼調用C庫函數的任何環境。 這是一些示例代碼。 如果沒有給出參數或參數太多,則打印用法消息並退出程序。 如果提供了一個參數,則將其轉換為整數並打印。
segment .text
global main
extern printf, atoi, sprintf, strlen, write
main:
.argc equ 0
.argv equ 4
segment .data
.f1 db "Usage: %s n", 0x0a, 0
.f2 db "%d", 0x0a, 0
segment .bss
.buf resb 255
segment .text
push rbp
mov rbp, rsp
sub rsp, 16
; Save the arguments.
mov [rsp+.argc], rdi
mov [rsp+.argv], rsi
; if (argc != 2)
cmp rdi, 2
jne .usage
; Convert argv[1] to an integer, then print it.
; We could have printed argv[1] as a string,
; but in an actual program we might want to do
; n = atoi(argv[1])
; because we are passing a number on the command line.
; printf("%d\n", atoi(argv[1]))
; Get argv[1].
mov rax, [rsp+.argv]
mov rdi, [rax+8] ; rdi gets *(argv + 1), or argv[1].
call atoi ; Return value in eax.
lea rdi, [.f2]
mov esi, eax
xor eax, eax
call printf
jmp .done
.usage:
; Get argv[0].
mov rax, [rsp+.argv]
mov rax, [rax]
; sprintf(buf, "Usage: %s n\n", argv[0])
lea rdi, [.buf]
lea rsi, [.f1]
mov rdx, rax
xor eax, eax
call sprintf
; len = strlen(buf);
lea rdi, [.buf]
call strlen ; string length is placed in eax.
; write(2, buf, strlen(buf))
mov edi, 2 ; fd for stderr
lea rsi, [.buf]
mov edx, eax
call write
.done:
leave
ret
假設上面的代碼包含在progname.asm中,則匯編和鏈接如下:
yasm -f elf64 -g dwarf2 -l progname.lst progname.asm
gcc progname.o -o progname
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.