动态链接程序如何在应用程序运行时解析引用?

时间:2020-09-02 15:07:34

标签: c linux gcc

假设我有一个源文件dll.c,该文件使用dlopendlsym函数在运行时加载名为F.so的共享库。

dll.c引用了some_function(),而F.so的定义是some_function()

假设下面的图片是可执行对象prog,它是通过

获得的
linux> gcc -rdynamic -o prog dll.c -ldl

enter image description here

因此.text部分包含some_function()的引用,在执行程序加载F.so并开始调用some_function()

时需要解决该引用

我的问题是:

第1季度对我来说,动态链接程序需要修改RAM(可执行文件复制到内存)中的.text部分(some_function()所属的部分),因此{ {1}}可以解决,我的理解正确吗?

Q2-如果动态链接程序需要修改RAM中的some_function()部分,该如何执行?据我了解,.text部分是RAM中的只读段,如果将其称为只读段,该如何修改只读段?

2 个答案:

答案 0 :(得分:1)

Q1-在我看来,动态链接程序需要修改RAM(可执行文件被复制到内存中)中的.text部分(some_function()所属的部分),以便可以解析some_function()的引用。 ,我的理解正确吗?

不必那样。有PLT(过程链接表)。基本上是这样的:

foo@PLT:
        jmp <someTemporaryAddress>
main:
        call foo@PLT

然后,在运行时,动态链接器仅修补此部分,因为它比在许多机器代码中查找调用更简单。

Q2-如果动态链接程序需要修改RAM中的.text部分,它如何执行?据我了解,.text段是RAM中的只读段,如果将其称为只读段,该如何修改只读段?

已将其设置为可执行/只读。

答案 1 :(得分:1)

Q1-在我看来,RAM(可执行文件被复制到内存中)中的.text部分(some_function()所属的部分)需要通过动态链接程序进行修改...

不。实际代码使用间接跳转:

.text
    ...
    call *xsome_function
    ...

.data
xsome_function:
    .long some_function

...因此,call指令不会跳转到某个地址,而是会跳转到存储在.data节中的某个地址。动态链接器必须替换行.long some_function中的地址,而不是call指令中的地址。

如果链接包含“直接” call指令的代码,则链接器将执行JCWasmx86在其答案中写的内容:

.text
    ...
    call some_function@PLT
    ...
some_function@PLT:
    jmp *xsome_function

.data
xsome_function:
    .long some_function

再一次,动态链接程序只需替换.data部分中的地址。

dlopen

如果您使用dlopendlsym访问您的库,则动态链接程序甚至不会替换任何内容:

dlsym()返回某个函数指针,该函数指针的处理方式与其他函数返回的任何其他指针一样(例如malloc()返回的指针)。调用dlsym()的程序负责以某种方式存储指针。

使用函数指针调用函数时,编译器将始终创建间接跳转指令(例如call %eax)。

第二季度-如果动态链接程序需要修改RAM中的.text部分,则...

几年前,我为Linux编写了一些小型编译器/链接器。

由于我来自Windows开发,而Window的动态链接器实际上替换了.text部分中的地址,因此我以与Windows下相同的方式编写了编译器/链接器:

结果:在运行使用我的编译器编译的程序时,动态链接器(ld-linux.so)只是崩溃,导致“分段错误”,因为动态链接器无法在Linux下写入.text段。 / p>

-编辑-

一个例子:

如果使用dlopen()dlsym(),则C代码看起来不是这样:

extern double sin(double x);
...
sine = sin(angle);

相反,C代码如下所示:

static double (*psin)(double x);
...
sofile = dlopen("libm.so",FLAGS);
psin = dlsym(sofile,"sin");
...
sine = psin(angle);