Skip to content

Blog#

C variables representation in ELF 1 - Sections

Previously, we've used gcc -S to stop assembling and gcc -c to stop linking, and explored C variables representation in assembly(gcc -S) and object(gcc -c).

The symbols in the intermediate object file (vars-section.o) are waiting to be relocated and resolved to determine their actual virtual address. It's the linker's turn.

After linking, all object files (*.o) are linked into one ELF. By default, it links dynamically and the type of outcome is DYN (position-independent executable file).

C Memory Order(Sequential Consistency)

The "happens before" relation is the only possible way to reason about timing between different threads. It is only established through synchronization that uses either atomic objects or very specific C library functions.

An atomic object can be used to synchronize two threads, if one thread writes a value and another thread reads the value that was written. Operations on atomics are guaranteed to be locally consistent.

Sequential consistency is the default consistency model for atomics, but not for other C library functions. It additionally assumes that all corresponding synchronization events are totally ordered.

volatile in C/C++

volatile (computer programming) - Why is volatile needed in C?

volatile in C actually came into existence for the purpose of not caching the values of the variable automatically. It will tell the compiler not to cache the value of this variable. So it will generate code to take the value of the given volatile variable from the main memory every time it encounters it. This mechanism is used because at any time the value can be modified by the OS or any interrupt. So using volatile will help us accessing the value afresh every time.

C Double Pointer(Pointer-to-Pointer)

Since pointers are variables themselves, they can be stored in arrays just as other variables can.

The pointer to a pointer in C is used when we want to store the address of another pointer.

C Pointers to Functions

There is yet another construct for which the address-of operator & can be used: functions.

A function pointer, also called a subroutine pointer or procedure pointer, is a pointer referencing executable code, rather than data. Dereferencing the function pointer yields the referenced function, which can be invoked and passed arguments just as in a normal function call. Such an invocation is also known as an "indirect" call, because the function is being invoked indirectly through a variable instead of directly through a fixed identifier or address.

Function pointers allow different code to be executed at runtime. They can also be passed to a function to enable callbacks.

The advantage of using function pointers is that multiple modules implementing the same function can be identified together, making maintenance easier and the system structure clearer. Or to summarise: it is easy to design layers, promotes system abstraction, reduces coupling and separates the interface from the implementation.