C++ internals explained with assembly: Part 1

Sasinda Rukshan
Jul 30, 2017 · 4 min read

I was playing with C++ language some time back and was wondering how it was still very fast and efficient while we could return by value instead of reference if wanted. And add to that there were these different concepts of copy and move semantics when constructing objects, two types of references LHS refs(& for actual memory addresses) and RHS refs(&& for literals and RHS values). So I wanted to dive deep and see what is actually happening under the hood.

Prerequisites:
Guide on Assembly lang for X86 instruction set, from University of Virginia
Then skim through X64(64-bit extensions to Intel’s and AMD’s 32-bit x86 instruction set)

Primer on x86-64 architecture

I am assuming you have gone through the above prerequisites. This is a short summery just for reference.

R?? are General purpose registers.. XMM? are for floating point operations and other SIMD (Single Instruction Multiple Data) operations.

x64 registers
Zoomed in on the GPRs

Programe Layout

Now that you know enough about x64 assembly lets examine how a C++ programe resides in memmory. About 1GB of RAM is set apart for the OS. Each program will get allocated some amount of memory depending on the available RAM and the programs requirements. The C++ binary will reside in the Text Segment (at the lowest memory address in the program’s memory). Notice the stack grows from high address to lower and heap from low address to higher.

The programe memory layout (Note: this is on RAM, the registers above are in the CPU itself)

For more information on how a c++ program is converted from source to executable, see http://www.tenouk.com/ModuleW.html. Above image summarizes the compilation process.

You may find https://gcc.godbolt.org as a useful tool to get x64 code directly. The hexadecimal numbers in the middle of the below code samples is the actual program, which will literally lie in the text segment above as binary numbers.

Given a simple C++ program as below you can get the corresponding assembly code by using the -S option to give the machine code in a readable format.

g++ -S -masm=intel test.cpp

The 32 bit integer x will be defined in the STACK, just above the base pointer at address [rbp-4]. int* ip (a 64 bit pointer, since addresses in x64 architecture is 64bit) will also be defined in the STACK at [rbp-16] and will be initialize with the address of the 4 bytes(DWORD) allocated on the HEAP. Declaration of MyStruct will define 2 integers in the stack ‘b’ at [rbp-20] and ‘a’ at [rbp-24]. static variable y will reside in the DATA section. ‘y’ will be referred relative to the instruction pointer (rip) i.e relative to the current address where the op code to access the static variable is defined in the TEXT section. There is no assembly instruction for defining y, since that will get hardcoded in the final binaries Data section. Thus TEXT = code, +DATA = initialized static vars, determine the size of the executable.

Classes methods, fields and static fields.

The static field of the class gets defined same as any other static field in the DATA section (here BSS section since it was not initialized)

MyClass only have one non static field. So it just need the same space as you would have declared a struct. It just allocates space for a 32 bit int in the main() stack when MyClass c is declared. The code copies the effective address(lea) of [rbp-4] to rdi(via rax) and calls constructor method. This is actually passing where the implicit ‘this’ variable is. i.e where the constructed object is.

The constructor copies rdi as the ‘this’ parameter in the prologue, and then initializes a. It knows where ‘this.a’ is since this was passed through rdi. You can see that even when calling c.m() the ‘this’ reference is passed through rdi and it is saved as the first local var in the m() at ebp-8 (since x64 addresses are 8bytes long).

Well with that I am gonna end this part, think you would have got a basic understanding of how a C++ program (or any other alike) would actually be converted to machine code and executed. In the next part let’s look at LHS and RHS refs, and virtual tables.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade