0

I am rather new to assembly and have been trying to understand what is happening with the call instruction within this code. I have this simple C++ program that I compiled and disassembled with gdb.

#include<iostream> using namespace std; int main() { int number, i, a, x; for (a = 1; a <= 9; a++) { for (i = 1; i <= 9; i++){ x = a * i; cout << a << " * " << i << " = " << x << endl; } } return 0; } 

Here is the disassembled code:

(gdb) disassemble main Dump of assembler code for function main: 0x0000000000000000 <+0>: push %rbp 0x0000000000000001 <+1>: mov %rsp,%rbp 0x0000000000000004 <+4>: sub $0x10,%rsp 0x0000000000000008 <+8>: movl $0x1,-0x8(%rbp) 0x000000000000000f <+15>: cmpl $0x9,-0x8(%rbp) 0x0000000000000013 <+19>: jg 0xa3 <main+163> 0x0000000000000019 <+25>: movl $0x1,-0xc(%rbp) 0x0000000000000020 <+32>: cmpl $0x9,-0xc(%rbp) 0x0000000000000024 <+36>: jg 0x9a <main+154> 0x0000000000000026 <+38>: mov -0x8(%rbp),%eax 0x0000000000000029 <+41>: imul -0xc(%rbp),%eax 0x000000000000002d <+45>: mov %eax,-0x4(%rbp) 0x0000000000000030 <+48>: mov -0x8(%rbp),%eax 0x0000000000000033 <+51>: mov %eax,%esi 0x0000000000000035 <+53>: lea 0x0(%rip),%rdi # 0x3c <main+60> 0x000000000000003c <+60>: callq 0x41 <main+65> 0x0000000000000041 <+65>: lea 0x0(%rip),%rsi # 0x48 <main+72> 0x0000000000000048 <+72>: mov %rax,%rdi 0x000000000000004b <+75>: callq 0x50 <main+80> 0x0000000000000050 <+80>: mov %rax,%rdx 0x0000000000000053 <+83>: mov -0xc(%rbp),%eax 0x0000000000000056 <+86>: mov %eax,%esi 0x0000000000000058 <+88>: mov %rdx,%rdi 0x000000000000005b <+91>: callq 0x60 <main+96> 0x0000000000000060 <+96>: lea 0x0(%rip),%rsi # 0x67 <main+103> 0x0000000000000067 <+103>: mov %rax,%rdi 0x000000000000006a <+106>: callq 0x6f <main+111> 0x000000000000006f <+111>: mov %rax,%rdx 0x0000000000000072 <+114>: mov -0x4(%rbp),%eax 0x0000000000000075 <+117>: mov %eax,%esi 0x0000000000000077 <+119>: mov %rdx,%rdi 0x000000000000007a <+122>: callq 0x7f <main+127> 0x000000000000007f <+127>: mov %rax,%rdx 0x0000000000000082 <+130>: mov 0x0(%rip),%rax # 0x89 <main+137> 0x0000000000000089 <+137>: mov %rax,%rsi 0x000000000000008c <+140>: mov %rdx,%rdi 0x000000000000008f <+143>: callq 0x94 <main+148> 0x0000000000000094 <+148>: addl $0x1,-0xc(%rbp) 0x0000000000000098 <+152>: jmp 0x20 <main+32> 0x000000000000009a <+154>: addl $0x1,-0x8(%rbp) 0x000000000000009e <+158>: jmpq 0xf <main+15> 0x00000000000000a3 <+163>: mov $0x0,%eax 0x00000000000000a8 <+168>: leaveq 0x00000000000000a9 <+169>: retq End of assembler dump. 

My main confusion are the call instructions that are pointing to the next line of code. It seems like the code is formatting the cout stream, however I don't see any call to cout in this function and I don't fully understand how it is even formatting the stream to begin with. Any help would be greatly appreciated.

Thanks

5
  • You don't see cout << aa and the following? Yes, these are calls. To the overloaded << operator. Note how the number of callq instructions matches the number of usages of << operators. Commented Nov 24, 2024 at 20:11
  • Can't reproduce. Here the calls go to reasonable addresses, and gdb annotates them with the name of the called function, which is indeed the appropriate operator<< overload in each case. If you set print asm-demangle on you will even see them in demangled human-readable form. Commented Nov 24, 2024 at 20:16
  • Can you show the commands you're using to compile and debug the program, as well as versions of gcc and gdb? Commented Nov 24, 2024 at 20:16
  • 2
    Are you by any chance running the debugger on the .o file (result of gcc -c) rather than the actual linked executable? That would have this effect. The .o file puts a zero in the displacement field of the call instruction, so it appears to go to the next instruction, but elsewhere in the file are relocation entries telling the linker what should actually go there in the executable. Tools like objdump --disassemble --reloc can annotate the disassembly with that information, but gdb won't, probably because debugging a .o file is not really meaningful in the first place. Commented Nov 24, 2024 at 20:19
  • 1
    @NateEldredge: Yeah, that's for sure what's going on. The LEA RIP-relative offsets are also 0, like lea 0x0(%rip),%rdi which is passing the address of std::cout, or others for strings. I didn't know you could run GDB on a non-linked .o, but it's not useful. Commented Nov 24, 2024 at 21:33

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.