1

In gcc assembly, the main function can either return or exit, where both work. Here I have two programs, where one exits with a syscall int $0x80, and the other simply calls ret. What is the difference?

.data
hello: .string "Hello, World!"
.globl main
main:
  push %rbx
  movq $hello, %rdi
  call puts
  pop %rbx

  ret

and

.data
hello: .string "Hello, World!"
.globl main
main:
  push %rbx
  movq $hello, %rdi
  call puts
  pop %rbx

  movq $1, %rax
  movq $0, %rbx
  int $0x80

I am aware that ret pops the instruction pointer off the stack, but what does that really do in this case?

Riolku
  • 572
  • 1
  • 4
  • 10
  • If you link with the _C_ runtime, it will do the `call main`. When you do a `ret` it returns to the _C_ runtime which eventually kills the process. The sys_exit syscall avoids returning back to the _C_ runtime that called main and requests the OS to stop the process. – Michael Petch Jul 15 '18 at 23:40
  • @MichaelPetch what if I don't link with c runtime(assuming I change my puts function, of course) – Riolku Jul 15 '18 at 23:52
  • @MichaelPetch Additionally, what are the differences between both options – Riolku Jul 15 '18 at 23:53
  • 1
    If you don't link with the runtime, and you are on linux, you simply can't use `ret` because there is nowhere to return to. – Jester Jul 15 '18 at 23:54
  • @Jester Cool, thanks – Riolku Jul 16 '18 at 00:05

1 Answers1

5

The code that calls main looks like this:

int status = main(argc, argv, envp);
exit(status);

if main returns, exit(status) is executed. exit is a C library function which flushes all stdio streams, invokes atexit() handlers and finally calls _exit(status), which is the C wrapper for the SYS_exit system call. If you use the C runtime (e.g. by having your program start at main or by using any libc functions), I strongly recommend you to never call SYS_exit directly so the C runtime has a chance to correctly deinitialize the program. The best idea is usually to call exit() or to return from main unless you know exactly what you are doing.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • This response looks like it was meant for a c question... my question is about assembly. Either way, the comments answer my question much better than this answer, sorry. – Riolku Jul 16 '18 at 00:13
  • 3
    @Riolku that C maps directly to asm on any platform. C is a common way of describing what asm does, as a short-hand. You can single-step into the actual asm that called your `main` by using GDB's `stepi` command to step past the `ret` at the end of `main`. In glibc for x86-64, the asm looks something like `call rax` / `mov edi, eax` / `call exit`, IIRC, and lives in libc itself. The CRT startup code passes it a function pointer to `main`. – Peter Cordes Jul 16 '18 at 01:04