0

I am on a Mac and I am trying to print a single character to stdout in X86 assembly. I have not found any examples on line that worked for me - however, this one came the closest. By assembling it like this: gcc -masm=intel print.asm I get this output:

Undefined symbols for architecture x86_64:
  "putchar", referenced from:
      _main in print-c2eebf.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Here is my clang version:

Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.62)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Here is my code:

    .global _main, putchar
    .text

_main:
    push 0x21  # put exclamation point on stack
    call putchar

    mov rdi, 0  # exit code of zero
    mov rax, 0x2000001
    syscall

This is really frustrating, I do not know how to make it work properly. Does anyone have a solution?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Caspian Ahlberg
  • 934
  • 10
  • 19
  • 1
    64 bit calling convention does not use stack to pass the first few arguments, circumstances permitting. Try `mov edi, '!'; call putchar` instead. Due to the linker error, you might need to use an underscore prefix, so `call _putchar`. Remove the `putchar` from the `.global` line as that is not a symbol you are trying to export. – Jester Sep 25 '20 at 18:39
  • @Jester It seems to compile now when I use _putchar, but it won't print out anything on screen. And when moving that value to edi, I get a segmentation fault. I removed putchar from the .global line - but it runs the same. Thank you for your tips though. – Caspian Ahlberg Sep 25 '20 at 18:42
  • 1
    `stdout` is typically line buffered. Since you use an exit syscall, that buffer might not be flushed. End your code with `ret` instead. – Jester Sep 25 '20 at 18:49
  • @Jester Still the same segmentation fault. I'll step through it with a debugger and let you know what I find – Caspian Ahlberg Sep 25 '20 at 19:02
  • @Jester Still the same segfault. If you have a mac, does what I did work for you? – Caspian Ahlberg Sep 25 '20 at 19:29
  • You have to re-align RSP before calling a library function. e.g. do a dummy `push rax`. [x64 nasm: pushing memory addresses onto the stack & call function](https://stackoverflow.com/q/13091987) shows how to call C library functions from NASM on MacOS. – Peter Cordes Sep 25 '20 at 20:17
  • See also [64-bit syscall documentation for MacOS assembly](https://stackoverflow.com/q/47834513) for making a `write` system call yourself. – Peter Cordes Sep 25 '20 at 20:20
  • @PeterCordes This is my code now - but it gives me this error: `print.asm:13:5: error: 32-bit absolute addressing is not supported in 64-bit mode lea rdi, [msg]` Here's my code: https://pastebin.com/gbXQShX4 Do you know why this is happening? Here's how I'm compiling it: `gcc -g3 -O0 -masm=intel print.asm` – Caspian Ahlberg Sep 25 '20 at 22:10
  • 1
    I forgot you were using GAS .intel_syntax, not NASM, when I linked duplicates. Use RIP-relative addressing modes, that's the point of using LEA at all. `lea rdi, [RIP + msg]`. Hopefully you found that yourself sometime after googling on that `32-bit absolute addressing is not supported in 64-bit mode` error. Note that `-O0` is irrelevant for asm source files; that's a C -> asm optimization option. – Peter Cordes Sep 26 '20 at 04:56
  • Also, if you do just want to call `_putchar`, you don't need any pointers to static data, just a character value in EDI. But anyway, see [Unable to move variables in .data to registers with Mac x86 Assembly](https://stackoverflow.com/q/50205129) for GAS syntax. – Peter Cordes Sep 26 '20 at 04:59
  • @PeterCordes Thank you, that resolved my problem. – Caspian Ahlberg Sep 27 '20 at 18:56

0 Answers0