У динамических библиотек один и тот же адрес виртуальной памяти во всех программах?

Когда библиотека динамически связана с программой, имеет ли она тот же адрес в этой программе, что и в любой другой программе?

В моей голове я представил, что каждый процесс получает все адресное пространство, а затем все в этом процессе (включая динамические библиотеки, которые уже находятся в памяти) сопоставляются с полуслучайными его частями из-за ASLR.

Но я провел небольшой эксперимент, который, кажется, подразумевает, что адреса библиотек, которые находятся в памяти, фиксированы для разных процессов и, следовательно, могут быть повторно использованы в программах? Это верно?

Я написал две короткие программы на c, в которых использовалась функция "сна". В одном я распечатал адрес функции сна, а во втором назначил указатель функции этому адресу. Я запустил их оба, и функция сна работала в обоих.

#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);
    }
}

Я не был уверен, что это покажет, но на самом деле это показало: а) адрес был тем же самым каждый раз, когда я запускал первую программу, и б) что сон все еще работал, когда я запускал вторую.

Думаю, я понимаю, как это работает, но мне любопытно, должно ли работать так, как работает, и каковы причины этого?

Чтобы сослаться на ответ, который я уже получил, когда взглянул на otool -IvV, я получил:

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

То же самое, что и косвенный адрес в lldb. Адрес был адресом самого сна:

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.

Для дополнительной информации:

$ 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

person AsksStupidQuestions    schedule 25.03.2019    source источник


Ответы (1)


В macOS многие системные библиотеки являются частью общего кэша dyld. Есть машинное отображение. Таким образом, эти библиотеки имеют один и тот же адрес во всех процессах одной архитектуры (32- или 64-разрядных).

Расположение общего кэша dyld выбирается случайным образом при загрузке системы. Таким образом, адреса библиотеки будут одинаковыми от процесса к процессу до перезагрузки.

Не все системные библиотеки являются частью кеша, только те, которые Apple считает обычно загружаемыми.

Ваши собственные или сторонние библиотеки будут загружаться в случайные места каждый раз при загрузке, если они не зависят от позиции.

Попробуйте посмотреть на вывод vmmap -v <pid>. Ищите строку с «подкартой виртуальной машины для всей машины» и те, что следуют за ней.

person Ken Thomases    schedule 25.03.2019
comment
У меня был собственный дилиб, и да, каждый раз, когда он загружался, он находился в новом месте, если я сохранял его загруженным (путем запуска программы, использующей его в бесконечном цикле), адреса были такими же, и я мог его получить из других программ. Мне нравится узнавать, как это работает. - person AsksStupidQuestions; 25.03.2019
comment
Я не ожидал, что если один процесс будет загружен, это повлияет на последующие процессы, которые его загружают. - person Ken Thomases; 25.03.2019
comment
Хм, ты прав, я думаю, меня обманули, потому что два младших байта адреса совпадали. - person AsksStupidQuestions; 25.03.2019
comment
Да, ASLR должен перемещать файлы только с приращением размера страницы (4096 a.k.a. 0x1000). Таким образом, он никогда не изменит младшие три шестнадцатеричные цифры. - person Ken Thomases; 25.03.2019