Linux kernel ld linux.so*本身是如何链接和加载的?

Linux kernel ld linux.so*本身是如何链接和加载的?,linux-kernel,linker,ld,loader,Linux Kernel,Linker,Ld,Loader,出于好奇,Linux动态链接器/加载程序是如何链接和加载的 上面的屏幕截图显示,文件和ldd似乎给出了矛盾的结果:一个说静态链接,另一个说动态链接 那么加载程序本身是如何加载的呢 ld linux.so*不依赖于任何其他库。当加载到内存时,它可以自己运行 ldd是一个脚本,它通过加载程序加载对象文件,加载程序检查对象是动态链接还是静态链接,请尝试以下操作: LD_TRACE_LOADED_OBJECTS=1/lib64/LD-linux-x86-64.so.2/lib64/LD-linux-x8

出于好奇,Linux动态链接器/加载程序是如何链接和加载的

  • 上面的屏幕截图显示,
    文件
    ldd
    似乎给出了矛盾的结果:一个说静态链接,另一个说动态链接

  • 那么加载程序本身是如何加载的呢

  • ld linux.so*
    不依赖于任何其他库。当加载到内存时,它可以自己运行

  • ldd
    是一个脚本,它通过加载程序加载对象文件,加载程序检查对象是动态链接还是静态链接,请尝试以下操作:


  • LD_TRACE_LOADED_OBJECTS=1/lib64/LD-linux-x86-64.so.2/lib64/LD-linux-x86-64.so.2

  • 文件
    读取幻数或elf头以确定对象是动态链接还是静态链接,它可能会输出与
    ldd不同的值
  • 在我看来,
    ld linux.so
    是静态链接的,因为它没有所有动态链接对象都必须具有的
    .interp
    部分

  • ld linux.so*
    不依赖于任何其他库。当加载到内存时,它可以自己运行

  • ldd
    是一个脚本,它通过加载程序加载对象文件,加载程序检查对象是动态链接还是静态链接,请尝试以下操作:


  • LD_TRACE_LOADED_OBJECTS=1/lib64/LD-linux-x86-64.so.2/lib64/LD-linux-x86-64.so.2

  • 文件
    读取幻数或elf头以确定对象是动态链接还是静态链接,它可能会输出与
    ldd不同的值
  • 在我看来,
    ld linux.so
    是静态链接的,因为它没有所有动态链接对象都必须具有的
    .interp
    部分。

    @臧明杰

    你的回答对我帮助很大,但下面的话可能会让一些人感到困惑:

    在IMO中,ld-linux.so是静态链接的,因为它没有所有动态链接对象都必须具有的.interp>部分

    我们应该将“所有动态链接对象”分为两部分,其中一类我们称为“共享对象”,如下所示:

    gcc -c -o test.o test.c -fPIC
    ld -o test.so test.o -shared
    
       void foobar(void){ while(1); }
    
    另一种称为“动态链接可执行文件”:

    gcc -c -o test.o test.c -fPIC
    ld -o test.so test.o
    
    有两点很重要:

    1,共享对象没有“.iNTERP”段,而动态链接的可执行文件有

    2、Linux内核不关心ELF文件是由ELF头指示的EXEC文件还是DYN文件。他首先搜索.INTERP段,如果失败,他将为每个加载类型段添加一个mmap(),并将控制传递给eheader->e_条目,无论他加载的是可执行文件还是共享对象

    由于ld-linux.so是一个常见的共享对象,所以她没有.INTERP段并不奇怪。她可以作为可执行文件运行并不奇怪。每个共享对象都可以

    编写如下代码:

    gcc -c -o test.o test.c -fPIC
    ld -o test.so test.o -shared
    
       void foobar(void){ while(1); }
    
    将其编译为共享对象(使用上面的命令行)。 运行它:

    您将使流程陷入死循环。 使用Ctrl-C中断它。您将看到(需要gcc的-g选项)

    你可以走得更远:

    (gdb) p $eip
    $1 = (void (*)()) 0x80000183 <foobar+3>
    (gdb) 
    
    (gdb)p$eip
    $1=(无效(*)()0x80000183
    (gdb)
    
    如果您熟悉linux内核,您应该知道0x8000000与内核变量“mmap_min_addr”的值有关。因为test.so是一个共享对象,所以她的加载地址为零,所以内核为她找到了一个默认的虚拟地址,即0x8000000,而不是0x804000

    我不知道我怎么会这么离题…

    @臧明杰

    你的回答对我帮助很大,但下面的话可能会让一些人感到困惑:

    在IMO中,ld-linux.so是静态链接的,因为它没有所有动态链接对象都必须具有的.interp>部分

    我们应该将“所有动态链接对象”分为两部分,其中一类我们称为“共享对象”,如下所示:

    gcc -c -o test.o test.c -fPIC
    ld -o test.so test.o -shared
    
       void foobar(void){ while(1); }
    
    另一种称为“动态链接可执行文件”:

    gcc -c -o test.o test.c -fPIC
    ld -o test.so test.o
    
    有两点很重要:

    1,共享对象没有“.iNTERP”段,而动态链接的可执行文件有

    2、Linux内核不关心ELF文件是由ELF头指示的EXEC文件还是DYN文件。他首先搜索.INTERP段,如果失败,他将为每个加载类型段添加一个mmap(),并将控制传递给eheader->e_条目,无论他加载的是可执行文件还是共享对象

    由于ld-linux.so是一个常见的共享对象,所以她没有.INTERP段并不奇怪。她可以作为可执行文件运行并不奇怪。每个共享对象都可以

    编写如下代码:

    gcc -c -o test.o test.c -fPIC
    ld -o test.so test.o -shared
    
       void foobar(void){ while(1); }
    
    将其编译为共享对象(使用上面的命令行)。 运行它:

    您将使流程陷入死循环。 使用Ctrl-C中断它。您将看到(需要gcc的-g选项)

    你可以走得更远:

    (gdb) p $eip
    $1 = (void (*)()) 0x80000183 <foobar+3>
    (gdb) 
    
    (gdb)p$eip
    $1=(无效(*)()0x80000183
    (gdb)
    
    如果您熟悉linux内核,您应该知道0x8000000与内核变量“mmap_min_addr”的值有关。因为test.so是一个共享对象,所以她的加载地址为零,所以内核为她找到了一个默认的虚拟地址,即0x8000000,而不是0x804000


    我不知道我怎么会偏离主题…

    LD_TRACE_LOADED_OBJECTS=1/lib64/LD-linux-x86-64.so.2/lib64/LD-linux-x86-64.so.2加载加载程序本身并计算加载了多少个对象?顺便问一下,一般来说,loader/lib64/ld-linux-x86-64.so.2本身是如何进入内存的?内核加载loader.so.2,并且loader使用open()和mmap()调用sld_TRACE_LOADED_OBJECTS=1/lib64/ld-linux-x86-64.so.2/lib64/ld-linux-x86-64.so.2加载loader本身并计算加载了多少个对象?顺便问一下,一般来说,loader/lib64/ld-linux-x86-64.so.2本身是如何进入内存的?内核加载loader.and loader使用open()和mmap()调用hanks来解释!这不是那么离题。谢谢你的解释!这不是那么离题。