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 { } }
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