0

I am trying to print the character h in assembly, but it is not outputting anything right now. I see no reason, nor can I understand why this is not working.

I would believe that it is because I am using %rbp instead of %eax but I am reasonably new to assembly, and I do not know whether writing to the %rbp register instead of %eax makes a difference.

.section .text
    .global _start
_start:
    mov %eax, %edi
    call main

    movl $1, %eax
    int $0x80
main:
    pushq %rbp
    movq %rsp, %rbp
    movl $4, %eax
    movl $1, %ebx
    push $0x068
    movl $5, %edx
    movq %rbp, %rsp
    syscall
    popq %rbp
    ret

The code is compiled with

> as $(BIN_DIR)/assembly.asm -o $(BIN_DIR)/a.o
> ld $(BIN_DIR)/a.o -o $(BIN_DIR)/a
ilittlebig
  • 31
  • 4
  • Why are you using `int $0x80` in 64-bit? – Joseph Sible-Reinstate Monica Sep 10 '21 at 20:25
  • 2
    Does this answer your question? [Using interrupt 0x80 on 64-bit Linux](https://stackoverflow.com/questions/22503944/using-interrupt-0x80-on-64-bit-linux) – Nate Eldredge Sep 10 '21 at 20:26
  • `int 0x80` is for 32-bit programs, 64-bit programs need to use the `syscall` API. See the link above. – Nate Eldredge Sep 10 '21 at 20:27
  • oh yeah, thank you, my bad – ilittlebig Sep 10 '21 at 20:27
  • Ok, please fix that and edit your post with the corrected code. I think there are some other issues but let's make sure we are dealing with one thing at a time. – Nate Eldredge Sep 10 '21 at 20:30
  • I edied the code, and it's still not outputting anything, there's another problem then – ilittlebig Sep 10 '21 at 20:31
  • You seem to have the system call arguments in all the wrong registers. See https://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-and-user-space-f, the "x86-64 Linux System Call convention" section. Also note that the second argument, in `%rsi`, needs to be a **pointer** to the data to be printed; if the data's on the stack, then you need to `mov %rsp, %rsi`. And don't pop the stack or adjust the stack pointer until the system call is done. – Nate Eldredge Sep 10 '21 at 20:33
  • 1
    Also system call numbers are different for `syscall` than for `int 0x80`; the `write` system call needs `rax = 1`, not 4. See https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md#x86_64-64_bit for a useful table which also shows which arguments to put in which registers. – Nate Eldredge Sep 10 '21 at 20:36
  • I solved it with that information. Thank you very much! – ilittlebig Sep 10 '21 at 21:18
  • Glad to hear it. Would you like to post an answer explaining what you found out? – Nate Eldredge Sep 10 '21 at 22:01

1 Answers1

0

I looked up the structure in e.g. Free Pascal sources which somewhat illustrates how parameters are allocated and how success is determined.

  movq sysnr, %rax        { Syscall number -> rax.  }
// for calls that have less parameters, just skip the relevant lines that load it
  movq param1, %rdi         { shift arg1 - arg5. }
  movq param2, %rsi
  movq param3, %rdx
  movq param4, %r10
  movq param5, %r8
  movq param6, %r9
  syscall                 { Do the system call. }
  cmpq $-4095, %rax       { Check %rax for error.  }
  jnae .LSyscOK           { Jump to error handler if error.  }
  negq  %rax
  movq  %rax,%rdi
  call  seterrno          // call some function to set errno threadvar 
  movq  $-1,%rax
.LSyscOK:                  // end of procedure
Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89