Writing to stderr in x86 assembly

I am new to assembly and I was wondering how to write output to stderr. I know that you can access the C functions of the standard library, such as printf, for printing on the console. But I can not understand how to print on stderr. I tried to use fprintf, but I just guess about the arguments, and I have no idea how to specify stderr as a file pointer. Thanks.

Edit: as suggested I tried this:

.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 

But it just called my program. Any other tips?

+4
source share
2 answers

Are you using fprintf from MSVCRT dll?

The first parameter is a pointer to the stream. Here is how you can use fprintf in assembly. In addition, when calling C functions from Assembly, you need to configure the stack after each call that you click on parameters.

Also, BIGGIE ... your NOT NULL line is terminated! You must NULL break your lines, as functions find the length of the line. Not sure if you are using Assembler, but you can do it in 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 
+7
source

I came here because I had problems writing stderr under Debian Linux. I use clarity because I'm looking at Ray Seyfart’s book. I write in Intel syntax and assembly for the elf64 format and the dwarf2 debugging protocol.

My first attempt to use fprintf met with a segmentation error. I looked at the insides of stdio. I managed to write the equivalent of one line:

  int main() { fprintf(stderr, "%d\n", 3); } 

But when I altered it altogether, I again started getting a segmentation error. My goal was to get the build equivalent:

  int main(int argc, char* argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %sn\n", argv[0]); } else { /* program code */ } } 

My final solution was to use the sprintf () call and then the write () system call using the file descriptor. A call to strlen () is also needed. This strategy should work in any environment in which C library function calls can be made from assembly code. Here is a sample code. If no arguments or too many arguments are given, a usage message is displayed and the program terminates. If one argument is provided, it is converted to an integer and printed.

  segment .text global main extern printf, atoi, sprintf, strlen, write main: .argc equ 0 .argv equ 4 segment .data .f1 db "Usage: %sn", 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: %sn\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 

Assuming the above code is contained in progname.asm, it is compiled and linked as follows:

  yasm -f elf64 -g dwarf2 -l progname.lst progname.asm gcc progname.o -o progname 
+1
source

Source: https://habr.com/ru/post/1437492/


All Articles