How to inspect Mach-O files
clang main.c
produces an a.out
,
which on macOS is a binary in the Mach-O (“Mach object”) format:
$ clang main.c
$ file a.out
a.out: Mach-O 64-bit executable x86_64
clang
produces Mach-O files when run on macOS
because the executable format in macOS is Mach-O.
By contrast, on Linux, clang
produces ELF files (“Executable and Linkable Format”),
because Linux’s executable format is ELF.
This is documented in man pages.
On macOS, the page for the execve
system call says:
execve()
transforms the calling process into a new process.
The new process is constructed from an ordinary file ...
This file is either an executable object file, or a file of data for an interpreter.
An executable object file consists of ... see a.out(5).
The page for a.out
says
The object files produced by the assembler and link editor are in Mach-O (Mach object) file format.
Since Mach-O files are just ordinary files, we can dig into the bits-and-bytes.
But we can also inspect Mach-O files with a tool called otool
(“object tool”).
For example, we can see what dynamic libraries our a.out
requires:
$ otool -L a.out
a.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
A .dylib
is a Mach-O dynamic module/library.
Our clang
decided that our program should depend on a dynamic library at /usr/lib/libSystem.B.dylib
.
This provides the implementations of many things used by C programs, such as stdio functions.
Dynamic libraries can themselves require dynamic libraries.
The big dylib at /usr/lib/libSystem.B.dylib
requires a bunch more dylibs:
$ otool -L /usr/lib/libSystem.B.dylib
/usr/lib/libSystem.B.dylib:
...
/usr/lib/system/libsystem_asl.dylib (compatibility version 1.0.0, current version 349.50.5)
/usr/lib/system/libsystem_blocks.dylib (compatibility version 1.0.0, current version 67.0.0)
/usr/lib/system/libsystem_c.dylib (compatibility version 1.0.0, current version 1158.50.2)
/usr/lib/system/libsystem_configuration.dylib (compatibility version 1.0.0, current version 888.60.2)
/usr/lib/system/libsystem_coreservices.dylib (compatibility version 1.0.0, current version 41.4.0)
...
An important dylib in here is /usr/lib/system/libsystem_c.dylib
.
It defines a bunch of functions used by C programs.
For example, this dylib defines the function fprintf
.
We can see this using a tool nm
(“name”), which shows the name/symbol table of a Mach-O file.
$ nm -g /usr/lib/system/libsystem_c.dylib | grep fprintf
000000000003ed45 T _fprintf
000000000003ee18 T _fprintf_l
0000000000046355 T _vfprintf
0000000000046308 T _vfprintf_l
Notice that the symbol is not fprintf
, but _fprintf
. This is because “The name of a symbol representing a function that conforms to standard C calling conventions is the name of the function with an underscore prefix”, according to Apple.
Tagged .
Similar posts
More by Jim
What does the dot do in JavaScript?
foo.bar
, foo.bar()
, or foo.bar = baz
- what do they mean? A deep dive into prototypical inheritance and getters/setters. 2020-11-01
Smear phishing: a new Android vulnerability
Trick Android to display an SMS as coming from any contact. Convincing phishing vuln, but still unpatched. 2020-08-06
A probabilistic pub quiz for nerds
A “true or false” quiz where you respond with your confidence level, and the optimal strategy is to report your true belief. 2020-04-26
Time is running out to catch COVID-19
Simulation shows it’s rational to deliberately infect yourself with COVID-19 early on to get treatment, but after healthcare capacity is exceeded, it’s better to avoid infection. Includes interactive parameters and visualizations. 2020-03-14
The inception bar: a new phishing method
A new phishing technique that displays a fake URL bar in Chrome for mobile. A key innovation is the “scroll jail” that traps the user in a fake browser. 2019-04-27
The hacker hype cycle
I got started with simple web development, but because enamored with increasingly esoteric programming concepts, leading to a “trough of hipster technologies” before returning to more productive work. 2019-03-23
Project C-43: the lost origins of asymmetric crypto
Bob invents asymmetric cryptography by playing loud white noise to obscure Alice’s message, which he can cancel out but an eavesdropper cannot. This idea, published in 1944 by Walter Koenig Jr., is the forgotten origin of asymmetric crypto. 2019-02-16
How Hacker News stays interesting
Hacker News buried my post on conspiracy theories in my family due to overheated discussion, not censorship. Moderation keeps the site focused on interesting technical content. 2019-01-26
My parents are Flat-Earthers
For decades, my parents have been working up to Flat-Earther beliefs. From Egyptology to Jehovah’s Witnesses to theories that human built the Moon billions of years in the future. Surprisingly, it doesn’t affect their successful lives very much. For me, it’s a fun family pastime. 2019-01-20
The dots do matter: how to scam a Gmail user
Gmail’s “dots don’t matter” feature lets scammers create an account on, say, Netflix, with your email address but different dots. Results in convincing phishing emails. 2018-04-07
The sorry state of OpenSSL usability
OpenSSL’s inadequate documentation, confusing key formats, and deprecated interfaces make it difficult to use, despite its importance. 2017-12-02
I hate telephones
I hate telephones. Some rational reasons: lack of authentication, no spam filtering, forced synchronous communication. But also just a visceral fear. 2017-11-08
The Three Ts of Time, Thought and Typing: measuring cost on the web
Businesses often tout “free” services, but the real costs come in terms of time, thought, and typing required from users. Reducing these “Three Ts” is key to improving sign-up flows and increasing conversions. 2017-10-26
Granddad died today
Granddad died. The unspoken practice of death-by-dehydration in the NHS. The Liverpool Care Pathway. Assisted dying in the UK. The importance of planning in end-of-life care. 2017-05-19
How do I call a program in C, setting up standard pipes?
A C function to create a new process, set up its standard input/output/error pipes, and return a struct containing the process ID and pipe file descriptors. 2017-02-17
Your syntax highlighter is wrong
Syntax highlighters make value judgments about code. Most highlighters judge that comments are cruft, and try to hide them. Most diff viewers judge that code deletions are bad. 2014-05-11
Want to build a fantastic product using LLMs? I work at
Granola where we're building the future IDE for knowledge work. Come and work with us!
Read more or
get in touch! This page copyright James Fisher 2017. Content is not associated with my employer. Found an error? Edit this page.