In last week’s episode we single stepped through the assembly code generated by the compiler, to see what happens when a function is called. We learned that selectors are just C strings, how they are stored and how to find them in the code.
Now we will use otool to explore the program as it’s saved on disk, so we can find the selector strings themselves. Compile the helloworld example from the previous episode. Click the disclosure arrow by Product. Open a terminal window, then type “cd ” (note the space following, it’s important) in the terminal and drag helloworld.app to the terminal to paste in the path.
Enter “otool -o helloworld | less” on the terminal. What you see is a list of all the objective-c classes defined in the executable, along with the protocols they adopt, and the ivars and methods they define. What you’re looking at here is the __OBJC segment of the executable.
Have a look at the MACH-O specification. Programs on disk are divided into segments. For simple C programs, there’s just __TEXT and __DATA. The __TEXT segment contains the assembly language from the compiled code and immutable constants. You can look at the generated code with otool -tV executable_file | less. If it’s a C++ program, also pipe it through c++filt to demangle the names. By using less’s search feature or the -p flag to otool you can find the compiled code corresponding to any function in your program.
The __DATA segment contains all the mutable constants declared in your program. Integer and shorter constants are just immediates in the code, e.g. MOV r0,7, but strings, arrays, and structs are put in the data segment.
Which leads us to sections. A segment is broken up into one or more sections. For example, the constant C strings are stored in the __cstring section of the __TEXT segment. Note that segment names are all caps, and section names are all lower case.
Enter otool -s __TEXT __cstring helloworld. If you compiled for both armv6 and armv7 you’ll notice that each architecture has its own cstring section. You’ll also notice that the output is in hex, with the load address as determined by the linker on the left, then the string data as 4-byte words. Add the -v flag and you’ll see the output as strings.
The segment and section for the selectors is __TEXT __objc_methname, so if you enter otool -arch armv7 -v -s __TEXT __objc_methname helloworld you’ll see all the selectors that your program calls as strings.
otool -arch armv7 -v -s __TEXT __objc_methname helloworld helloworld: Contents of (__TEXT,__objc_methname) section 000036ec release 000036f4 init 000036f9 alloc 000036ff window 00003706 viewController 00003715 setWindow: 00003720 setViewController: 00003733 dealloc …
Now that we know what selectors our program calls, the next step is to determine which ones correspond to illegal calls.
Tune in next week for the exciting conclusion! In the mean time, read up on the mach-o specification and otool, there is a lot of interesting information you can query out of a program.