skip to Main Content

I have this simple C program in a file named test.c :

void fx2(){

    int c = 30;
    c++;
}

void fx1(){

    int b = 20;
    b++;
    fx2();

}

int main(){

    int a = 10;
    a++; 
    fx1();
}

I’ve compiled this in an Ubuntu ( 22.04.3 ) x86_64 system by using "gcc test.c -o test".
Then I used "objdump -d test" and I got this :

0000000000001129 <fx2>:
    1129:   f3 0f 1e fa             endbr64 
    112d:   55                      push   %rbp
    112e:   48 89 e5                mov    %rsp,%rbp
    1131:   c7 45 fc 1e 00 00 00    movl   $0x1e,-0x4(%rbp)
    1138:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
    113c:   90                      nop
    113d:   5d                      pop    %rbp
    113e:   c3                      ret    

000000000000113f <fx1>:
    113f:   f3 0f 1e fa             endbr64 
    1143:   55                      push   %rbp
    1144:   48 89 e5                mov    %rsp,%rbp
    1147:   48 83 ec 10             sub    $0x10,%rsp
    114b:   c7 45 fc 14 00 00 00    movl   $0x14,-0x4(%rbp)
    1152:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
    1156:   b8 00 00 00 00          mov    $0x0,%eax
    115b:   e8 c9 ff ff ff          call   1129 <fx2>
    1160:   90                      nop
    1161:   c9                      leave  
    1162:   c3                      ret    

0000000000001163 <main>:
    1163:   f3 0f 1e fa             endbr64 
    1167:   55                      push   %rbp
    1168:   48 89 e5                mov    %rsp,%rbp
    116b:   48 83 ec 10             sub    $0x10,%rsp
    116f:   c7 45 fc 0a 00 00 00    movl   $0xa,-0x4(%rbp)
    1176:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
    117a:   b8 00 00 00 00          mov    $0x0,%eax
    117f:   e8 bb ff ff ff          call   113f <fx1>
    1184:   b8 00 00 00 00          mov    $0x0,%eax
    1189:   c9                      leave  
    118a:   c3                      ret    

I’ve also compiled test.c in a macOS ( Monteray 12.6.5 ) x86_64 system with "clang test.c -o test". Then I used "otool -tV test" and I got this :

(__TEXT,__text) section
_fx2:
0000000100003f40    pushq   %rbp
0000000100003f41    movq    %rsp, %rbp
0000000100003f44    movl    $0x1e, -0x4(%rbp)
0000000100003f4b    movl    -0x4(%rbp), %eax
0000000100003f4e    addl    $0x1, %eax
0000000100003f51    movl    %eax, -0x4(%rbp)
0000000100003f54    popq    %rbp
0000000100003f55    retq
0000000100003f56    nopw    %cs:(%rax,%rax)
_fx1:
0000000100003f60    pushq   %rbp
0000000100003f61    movq    %rsp, %rbp
0000000100003f64    subq    $0x10, %rsp
0000000100003f68    movl    $0x14, -0x4(%rbp)
0000000100003f6f    movl    -0x4(%rbp), %eax
0000000100003f72    addl    $0x1, %eax
0000000100003f75    movl    %eax, -0x4(%rbp)
0000000100003f78    callq   _fx2
0000000100003f7d    addq    $0x10, %rsp
0000000100003f81    popq    %rbp
0000000100003f82    retq
0000000100003f83    nopw    %cs:(%rax,%rax)
0000000100003f8d    nopl    (%rax)
_main:
0000000100003f90    pushq   %rbp
0000000100003f91    movq    %rsp, %rbp
0000000100003f94    subq    $0x10, %rsp
0000000100003f98    movl    $0xa, -0x4(%rbp)
0000000100003f9f    movl    -0x4(%rbp), %eax
0000000100003fa2    addl    $0x1, %eax
0000000100003fa5    movl    %eax, -0x4(%rbp)
0000000100003fa8    callq   _fx1
0000000100003fad    xorl    %eax, %eax
0000000100003faf    addq    $0x10, %rsp
0000000100003fb3    popq    %rbp
0000000100003fb4    retq

Here’s my questions :

  1. Considering this simple C program can I be 100% sure that otool and objdump show the exact machine instructions contained in the executable test ? For example are the two function prologue instructions pushq %rbp and movq %rsp,%rbp" really contained in the actual executuable "test" or these disassemblers can omit/add/modify instructions to make the program easier to read and follow ?

  2. Looks like gcc and clang in Ubuntu and macOS respectively do use the frame pointers. Can we say that Ubuntu and macOS systems do use frame pointers or it would be more appropriate to say that only the specific compilers gcc and clang in the context of Ubuntu and macOS respectively use the frame pointer ?

2

Answers


    1. Disassemblers typically emit exactly the instructions found in the executable. They may have some trouble where binary data is interspersed with instructions in a way that doesn’t confuse the processor but may make it hard for the disassembler to decide where code continues. For example, the clang compiler seems to generate "nonsense" bytes as padding so that the next function starts on a 16-byte boundary which has advantages for cache behavior. The disassembler doesn’t know this and tries to interpret them as instructions.
    2. Use of frame pointers (and which registers are used for parameter and return value passing) is part of an ABI or calling convention which is often given for a platform (operating system) and followed by the compilers for that platform. Some languages may use different calling conventions internally but use the standard platform convention when interfacing with C library code.
    Login or Signup to reply.
  1. Considering this simple C program can I be 100% sure that otool and objdump show the exact machine instructions contained in the executable test ? For example are the two function prologue instructions pushq %rbp and movq %rsp,%rbp" really contained in the actual executuable "test" or these disassemblers can omit/add/modify instructions to make the program easier to read and follow ?

    They cannot always show the “exact” machine instructions since relocations may occur when the executable is assigned addresses in memory and addresses in the instruction stream are updated as the program is loaded.

    Aside from that, they should show the actual instructions in the executable, aside from using different mnemonics or variations in display that have the same meaning, possibly including using mnemonics for multiple instructions.

    Looks like gcc and clang in Ubuntu and macOS respectively do use the frame pointers. Can we say that Ubuntu and macOS systems do use frame pointers or it would be more appropriate to say that only the specific compilers gcc and clang in the context of Ubuntu and macOS respectively use the frame pointer ?

    Both Clang and GCC have a switch not to use a frame pointer, -fomit-frame-pointer, so clearly they do not always use a frame pointer. From experience using this in high-performance code, the primary effect of not using the frame pointer was that it disrupts debugging, since a debugger, at least in the macOS environment, relied on the frame pointer for some information about routines further up in the call tree.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search