聘我网

新概念招聘3.0

为何用dlsym 得到的函数地址和动态解析的地址不一样?

vote up0vote downstar
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char **argv)
{
   void *handle;
   double (*cosine)(double);
   char *error;

   handle = dlopen ("libm.so", RTLD_LAZY);
   if (!handle) {
      fprintf (stderr, "%s\n", dlerror());
      exit(1);
    }

    dlerror(); /* Clear any existing error */
    cosine = dlsym(handle, "cos");
    if ((error = dlerror()) != NULL) {
      fprintf (stderr, "%s\n", error);
      exit(1);
     }

     printf ("%f\n", (*cosine)(0));
     dlclose(handle);
     printf("%x\n", cosine);
     func();
     return 0;
}

void func()
{
    printf("%f\n", cos(0));
    printf("%x\n", cos);
} 

编译执行

gcc -Wall dlsym.c -lm -ldl && ./a.out

输出:

1.000000
13e19c70
1.000000
400630

这是为何?

 

1 个答复

vote up0vote downcheck

直接cos得到的是plt里的地址 (objdump能看见一个叫cos@plt的东西,就是它)

plt里面jmp到真正的函数的地址那里。

dlsym直接得到的就是真实的地址。

0000000000400630 <cos@plt>:
~~~~~~~~~~~~~~~~~~~ func里面打的是这个地址
  400630:       ff 25 6a 06 20 00       jmpq   *0x20066a(%rip)        # 600ca0 <_GLOBAL_OFFSET_TABLE_+0x30>
                                                ~~~~~~~~~~~~~~~ 这里jump过去的就是dlsym返回的那个地址 (实际情况比这一句话描述的稍微复杂一点,因为plt里面也有lazy binding)
  400636:       68 03 00 00 00          pushq  $0x3
  40063b:       e9 b0 ff ff ff          jmpq   4005f0 <_init+0x18>
链接

您的回答





不是您要找的问题? 浏览其他含有标签 的问题或者 自己问个.