0

I apologize if this is a naive question, but I was wondering what the difference is between the "Disassembly" and the "Assembly" that XCode is able to generate. The assembly is:

enter image description here

And the "Disassembly":

enter image description here

I suppose the difference is that Assembly includes some debug and Dwarf information whereas the Disassembly is stripped of all symbols and generated from (I think?) the executable file without any debugging turned on. Is this accurate, or what might be the differences? When debugging a program, what is usually looked at, if you have access to both?

samuelbrody1249
  • 4,379
  • 1
  • 15
  • 58

1 Answers1

2

Assembly is the compiler's text output (from clang -S), and will include labels instead of numeric branch targets. Disassembly can only give you symbolic names for anything that made it into the symbol table.

clang's -S output uses asm comments, e.g. for SIMD shuffle instructions. For FP bit-patterns, it shows the value represented: https://godbolt.org/z/efz1fq shows how float f = 1.25; compiles with clang for x86-64 (stripping out a bunch of "obvious" and less-interesting directives like .section .data)

f:
        .long   0x3fa00000                      # float 1.25

gcc -fverbose-asm adds the C names of the operands as comments to each instruction, but clang -fverbose-asm doesn't do much if anything.

.loc is debug metadata, C/C++ source line number. .cfi_* is backtrace info (Call Frame Information) which will end up in a .eh_frame section.


For perf tuning / seeing how something compiled, I normally prefer compiler asm output, not disassembly, but with noise like CFI and .loc directives filtered out (How to remove "noise" from GCC/clang assembly output?). Seeing labels on branch targets so you know when a location can be jumped to from elsewhere is very very useful to notice the tops of loops. (Some disassemblers like Agner Fog's objconv can disassemble into source that's ready to reassemble, with auto-numbered label names like compilers use.)

If you use link-time optimization, it's a good idea to look at that to get the true picture after cross-file inlining, because it's different code-gen than the usual -S -O3 output. That might mean disassembly of the binary, unless your tools can ask the link-time optimizer to print asm text.

For actual debugging, debuggers like GDB give you the option of using source-level debugging with C code and line numbers, and using the debug info to associate C names with register or memory locations. Normally you'd use that, but if you want to sanity check the logic to see if it compiled the way you expect, most debuggers make it easy to single-step by instruction in a disassembly view. (e.g. sometimes you'll notice that you used the wrong variable name because a bunch of stuff optimizes away and the asm is much simpler than you expected. Or that your branch condition was actually checking or (|) instead of short-circuit logical ||.)

In complex code, single-stepping in disassembly view is a good way to see what it's doing, to at least find the main loop or the path of execution that a specific input takes.

The -S compiler-generated asm text is not usually available while debugging. Clang doesn't generate it at all unless you ask for it. (GCC always generates a .s and runs as on it, separately from the cc1 C->asm compiler, and can save it if you ask). But there isn't metadata associating code addresses in the running program with .s asm lines, so it's not easy to use while really debugging.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847