Let's focus only on Rect_IsEmpty()
function.
The nm
command gives me this output:
(...)
00021af0 T Rect_IsEmpty
(...)
On the other hand, when I launch gdb
and see the address of this function, I get:
(gdb) info address Rect_IsEmpty
Symbol "Rect_IsEmpty" is at 0x8057c84 in a file compiled without debugging.
Could anyone, please, explain why these addresses are not the same? Where does gdb get this address from?
nm
gives you mangled name symbol table's address offset while gdb
gives you actual virtual process's memory address which is changed every time you run the process. (Before run
or start
in GDB, it uses the same method as nm
to get symbol addresses, using the same placeholder base address in PIE executables.)
nm
is just a tool which shows you offset from the beginning of the code segment. In your case:
00021af0 T Rect_IsEmpty
simply means, that the symbol Rect_IsEmpty
would have address 00021af0
if the executable were mapped at an image base of 0x1000
, a dummy placeholder value that ld
uses by default when linking a PIE. Normally the code segment is first with .text
at the start of that, so the start of it will show an address of 0x1000
in nm
or objdump -d
.
When running a Position-Independent Executable on Linux, the ASLR mechanism is used for randomizing the base addresses of the whole thing, to something other than 0x1000
. (Segments keep the same relative offset from each other, so PC-relative addressing can work, e.g. for x86-64 RIP-relative addressing of .data
and .rodata
from .text
.)
GDB disables actual randomization, but the kernel still uses a high base address, not 0x1000
. It will be the same one every time.
(If you built a traditional non-PIE executable, the kernel would have no choice where to load it, it would be the linker's choice, for example at 0x400000
, which nm
and objdump
can see, as could GDB without starting the program. gcc -fno-pie -no-pie
if you want that.)
When looking up the address of the function using debugger, you see the address of a symbol inside the process' code segment after having ASLR already done its job.
Here is a good article from IBM about shared libraries and another one about Procedure Linkage Table and Global Offset Table.