I'm using otool on macOS to disassemble some simple C programs I built in order to gain a better understanding of assembly language. I disassembled three programs, all of which consist of a single printf statement. One prints the string "Hello, World!\n", one prints a single integer formatted as a decimal, and the other prints two integers formatted as decimals.

My question regards the instruction call _printf. The disassembly doesn't show _printf; it shows the address of the _printf symbol. I get a different address each time. At first I thought this was because gcc converts any printf that doesn't use additional parameters to puts, but when I disassembled the third program I got still another address for printf. The code looks like this:

First program:

0000000100000f76        callq   0x100000f82

Second program:

0000000100000f7e        callq   0x100000f8a

Third program:

0000000100000f7a        callq   0x100000f86

I would like to gain a better understanding of how the glibc symbols are laid out in the executable. I am of course using the Mach-O format, but I have a feeling this variation in addresses is more universal. Also, given that the address is more or less random, how can one tell from the disassembly what function is being called?

  • 2
    how do you disassemble it? can you paste a bigger snippet around the call? – Igor Skochinsky Apr 24 '17 at 21:39

the addresses are different because the binaries are not identical and differ in their layout.

as for finding out which functions are being called:

easy solution: use -V to have otool print hints about the symbols being called.

hard solution: disassemble target addresses and figure out how the dynamic calls work in OS X and how dyld resolves symbols. it may be useful to use a debugger here and consult source code of dyld and ld(available at Apple 's open source website)

This appears to be a relative call. In a relative call in 32-bit assembly, the operand is added to the address of the next instruction (instruction right after the call). Keep in mind the the operand would be signed in this case.

Unfortunately, I don't know 64-bit assembly, but it seems to be similar.

If you look at the addresses for program one and program two, you can see that the difference is 8. This is the same with their operands, so it isn't random.

Hear is a link describing calls in more detail.

I couldn't find as good of an example for 64-bit.

Try searching around for relative calls if that doesn't clear it up.

  • 1
    I don't think that's the problem here. otool prints already resolved target addresses. – Igor Skochinsky Apr 26 '17 at 7:24

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.