3

This piece of code prints Hello on the screen

.data
    hello: .string "Hello\n"
    format: .string "%s" 
.text
    .global _start 
    _start:

    push $hello
    push $format
    call printf

    movl $1, %eax   #exit
    movl $0, %ebx
    int $0x80

But if I remove '\n' from hello string, like this:

.data
    hello: .string "Hello"
    format: .string "%s" 
.text
    .global _start 
    _start:

    push $hello
    push $format
    call printf

    movl $1, %eax   #exit
    movl $0, %ebx
    int $0x80

Program doesn't work. Any suggestions?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Dima
  • 152
  • 2
  • 11

2 Answers2

7

The exit syscall (equivalent to _exit in C) doesn't flush the stdout buffer.

Outputting a newline causes a flush on line-buffered streams, which stdout will be if it is pointed to a terminal.

If you're willing to call printf in libc, you shouldn't feel bad about calling exit the same way. Having an int $0x80 in your program doesn't make you a bare-metal badass.

At minimum you need to push stdout;call fflush before exiting. Or push $0;call fflush. (fflush(NULL) flushes all output streams)

  • Or use `puts`, or include a newline in what you're printing. Although that would only fix it for a terminal, not a pipe, so yes, don't mix stdio with raw _exit system calls. [Using printf in assembly leads to empty output when piping, but works on the terminal](https://stackoverflow.com/q/38379553) – Peter Cordes Jun 12 '22 at 22:33
3

You need to clean up the arguments you passed to printf and then flush the output buffer since you don't have new line in your string:

.data
    hello: .string "Hello"
    format: .string "%s" 
.text
    .global _start 
    _start:

    push $hello
    push $format
    call printf
    addl $8, %esp
    pushl stdout
    call fflush
    addl $4, %esp
    movl $1, %eax   #exit
    movl $0, %ebx
    int $0x80
  • You don't actually need to clean the stack if you're going to end with an `_exit(0)` system call. `_start` isn't a function so there's nowhere you can `ret` to anyway. The only important thing here is `fflush(NULL)` or `fflush(stdout)` before the raw `_exit` syscall (instead of `call exit`). To be fair, it is important to learn how the stack works if you want to write functions eventually. So realize that you're leaving stack args unpopped, and instead of another push, you could `movl $0, (%esp)` / `call fflush` to reuse one of the stack slots you reserved by pushing args for printf. – Peter Cordes Jun 12 '22 at 22:32