How can I get a reference to standard input from assembly on a mac?

Viewed 32

I'm following along in some books on assembler and find that they happily use fprintf with stdout. They simply reference stdout as a known symbol. I tried to do that in my code, and the linker complains that stdout is not found. I tried variation on spelling including a leading underscore. I also disassembled printf. It sets up a call to vfprintf using the following line:

leaq   0x41879948(%rip), %rax    ; __stdoutp

So it seems like I should be able to do something like:

leaq __stdoutp(%rip), %rdi

Didn't work. Linker complains of undefined symbol. Tried with variations. Left off the p suffix, one or both of the underscores. Nothing worked.

Any ideas, or insider knowledge I can follow to access to this symbol?

1 Answers

Based on @PeterCordes suggestion of looking at the compiler generated asm, I wrote a c program:

#include <stdio.h>
int main() { fprintf(stdout, "Hello, world!\n"); }

ran clang -S main.c on it, and had a look at the asm. Here's how clang generated asm is accessing the stdout global

    movq    ___stdoutp@GOTPCREL(%rip), %rax
    movq    (%rax), %rdi

Turns out this is stated in the ABI (section 3.5.4)

Position-independent code cannot contain absolute address. To access a global symbol the address of the symbol has to be loaded from the Global Offset Table. The address of the entry in the GOT can be obtained with a %rip-relative instruction in the small model.

stdout in the c code refers to the __stdoutp symbol. This becomes ___stdoutp in assembler, because macosx. Similar to how main is _main.

ABI section 5.2 explains GOT this way

Global offset tables hold absolute addresses in private data, thus making the addresses available without compromising the position-independence and shareability of a program’s text.

Related