【问题标题】:Do dynamic libraries have the same virtual memory address in all programs?动态库是否在所有程序中具有相同的虚拟内存地址?
【发布时间】:2019-03-25 11:12:25
【问题描述】:

当一个库动态链接到一个程序时,它在该程序中的地址是否与在任何其他程序中的地址相同?

在我的脑海中,我想象每个进程都获得了整个地址空间,然后由于 ASLR,该进程中的所有内容(包括已经在内存中的动态库)都被映射到其中的半随机部分。

但是我做了一个简短的实验,似乎暗示内存中的库地址在不同的进程中是固定的,因此可以跨程序重用?对吗?

我编写了两个使用“睡眠”功能的简短 c 程序。在一个中,我打印出 sleep 函数的地址,在第二个中,我为该地址分配了一个函数指针。我同时运行了它们,并且睡眠功能在两者中都有效。

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

我不确定这会显示什么,但它实际显示的是 a) 每次运行第一个程序时地址都是相同的 b) 当我运行第二个程序时睡眠仍然有效。

我想我理解它是如何工作的,但我很好奇它是否必须按照它的方式工作,背后的原因是什么?

只是为了参考我在查看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 中的间接地址。该地址是 sleep 本身的地址:

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

【问题讨论】:

    标签: macos dynamic-linking virtual-address-space


    【解决方案1】:

    在 macOS 上,许多系统库是 dyld 共享缓存的一部分。有一个机器范围的映射。因此,这些库在同一架构(32 位或 64 位)的所有进程中最终位于同一地址。

    dyld 共享缓存的位置在系统启动时是随机的。因此,在您重新启动之前,各个进程的库地址将是相同的。

    并非所有系统库都是缓存的一部分,只有 Apple 认为通常会加载的系统库。

    您自己或第三方的库每次加载时都会在随机位置加载,假设它们与位置无关。

    尝试查看vmmap -v &lt;pid&gt; 的输出。查找带有“机器范围的 VM 子图”的行以及后面的行。

    【讨论】:

    • 我尝试了自己的 dylib,是的,每次加载它时,它都在一个新位置,如果我一直加载它(通过在无限循环中运行一个使用它的程序)地址是一样的,我可以从其他程序中得到它。喜欢学习这些东西的工作原理。
    • 我不希望保留一个加载它的进程会影响加载它的后续进程。
    • 嗯,你是对的,我想我被愚弄了,因为地址的最低两个字节是相同的。
    • 是的,ASLR 应该只移动页面大小的增量(4096 又名 0x1000)。所以,它永远不会改变低三位十六进制数字。
    猜你喜欢
    • 2022-01-12
    • 2014-08-30
    • 1970-01-01
    • 2011-04-02
    • 2014-01-16
    • 2018-07-09
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多