Reputation: 149
When a library is dynamically linked to a program does it have the same address in that program as in any other program?
I my head I imagined each process gets the whole of the address space and then everything in that process (inc. dynamic libraries that are already in memory) gets mapped to semi-random parts of it because of ASLR.
But I did a short experiment that seems to imply that the address of libraries that are in memory are fixed across different processes and thus reusable across programs? Is that correct?
I wrote two short c programs which used the "sleep" function. In one I printed out the address of the sleep function and in the second I assigned a function pointer to that address. I ran them both and the sleep function worked in both.
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1)
{
printf("%s\n", &"hi");
sleep(2);
printf("pointer to sleep: %p\n", sleep);
}
}
#include <stdio.h>
#include <unistd.h>
#define sleepagain ((void (*)(int))0x7fff7652e669) //addr of sleep from first program
int main()
{
while(1)
{
printf("%s\n", &"test");
sleepagain(2);
}
}
I wasn't sure what this would show but what it actually showed was a) the address was the same every time I ran the first program and b) that sleep still functioned when I ran the second.
I think I understand how this works but I am curious if it has to work the way it does and what are the reasons behind it?
Just to reference the answer I got already when I took a look with otool -IvV
I got:
a.out:
Indirect symbols for (__TEXT,__stubs) 2 entries
address index name
0x0000000100000f62 2 _printf
0x0000000100000f68 3 _sleep
Indirect symbols for (__DATA,__nl_symbol_ptr) 2 entries
address index name
0x0000000100001000 4 dyld_stub_binder
0x0000000100001008 ABSOLUTE
Indirect symbols for (__DATA,__got) 1 entries
address index name
0x0000000100001010 3 _sleep
Indirect symbols for (__DATA,__la_symbol_ptr) 2 entries
address index name
0x0000000100001018 2 _printf
0x0000000100001020 3 _sleep
Which is also what the indirect address was in lldb. The address was the address of sleep itself:
Process 11209 launched: 'stuff/a.out' (x86_64)
hi
Process 11209 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff7652e669 libsystem_c.dylib`sleep
libsystem_c.dylib`sleep:
-> 0x7fff7652e669 <+0>: push rbp
0x7fff7652e66a <+1>: mov rbp, rsp
0x7fff7652e66d <+4>: push rbx
0x7fff7652e66e <+5>: sub rsp, 0x28
Target 0: (a.out) stopped.
For some additional info:
$ otool -hv a.out
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL LIB64 EXECUTE 15 1296 NOUNDEFS DYLDLINK TWOLEVEL PIE
Upvotes: 3
Views: 1043
Reputation: 90671
On macOS, many system libraries are part of the dyld shared cache. There's a machine-wide mapping. So, those libraries end up at the same address in all processes of the same architecture (32- or 64-bit).
The location of the dyld shared cache is randomized at system boot. So, library addresses will be the same from process to process until you reboot.
Not all system libraries are part of the cache, only the ones that Apple deems to be commonly loaded.
Libraries of your own or from third parties will be loaded at random locations each time they're loaded, assuming they are position-independent.
Try looking at the output from vmmap -v <pid>
. Look for the line with "machine-wide VM submap" and those that follow.
Upvotes: 4