可执行程序,是怎么“动”起来的

  • ldd只能对共享对象,也就是动态可执行文件使用。

ldd prints the shared objects (shared libraries) required by each program or shared object specified on the command line.

  • 对/bin/sh程序使用ldd,查看其依赖的库
  • 对自己写的程序使用ldd,可以看到,每次执行ldd的时候,每个依赖库所映射的地址都不一样,这可能和我们马上要探索的可程序“动起来”的过程有关。和安全也有一定的关系。
  • ldd man page中的解释如下:

In the usual case, **ldd **invokes the standard dynamic linker (see ld.so(8)) with the **LD_TRACE_LOADED_OBJECTS **environment variable set to 1. This causes the dynamic linker to inspect the program's dynamic dependencies, and find (according to the rules described in ld.so(8)) and load the objects that satisfy those dependencies. For each dependency, **ldd **displays the location of the matching object and the (hexadecimal) address at which it is loaded. (The linux-vdso and ld-linux shared dependencies are special; see vdso(7) and ld.so(8).)

  • 简单来说,ldd实际是调用标准链接器来得到依赖关系。ldd会显示以来的共享库以及加载时在可执行程序的虚拟地址空间中。

  • 在ld.so的man page中,可以看到,实际上,除了我们使用ldd这种方式来调用动态链接器外,也可以直接用下面这样的方式来获取我们需要的信息:

LD_TRACE_LOADED_OBJECTS If set (to any value), causes the program to list its dynamic dependencies, as if run by ldd(1), instead of running normally.

  • 动态链接器还会在动态可执行程序被执行的时候自动被调用,动态链接器保存在ELF文件中的.interp section中。
  • 当然了,我们主要关注的还是ELF中的动态链接是如何进行的。

看看hello的结构:
ELF Header

thorn@ubuntu:~/LinuxKernel/menu$ readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048736
  Start of program headers:          52 (bytes into file)
  Start of section headers:          724012 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         6
  Size of section headers:           40 (bytes)
  Number of section headers:         31
  Section header string table index: 28

section headers

thorn@ubuntu:~/LinuxKernel/menu$ readelf -S hello
There are 31 section headers, starting at offset 0xb0c2c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480f4 0000f4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            08048114 000114 000024 00   A  0   0  4
  [ 3] .rel.plt          REL             08048138 000138 000070 08  AI  0  23  4
  [ 4] .init             PROGBITS        080481a8 0001a8 000023 00  AX  0   0  4
  [ 5] .plt              PROGBITS        080481d0 0001d0 0000e0 00  AX  0   0 16
  [ 6] .text             PROGBITS        080482b0 0002b0 07201c 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080ba2d0 0722d0 000a6d 00  AX  0   0 16
  [ 8] __libc_thread_fre PROGBITS        080bad40 072d40 00009e 00  AX  0   0 16
  [ 9] .fini             PROGBITS        080bade0 072de0 000014 00  AX  0   0  4
  [10] .rodata           PROGBITS        080bae00 072e00 01a88c 00   A  0   0 32
  [11] __libc_subfreeres PROGBITS        080d568c 08d68c 000028 00   A  0   0  4
  [12] __libc_atexit     PROGBITS        080d56b4 08d6b4 000004 00   A  0   0  4
  [13] __libc_thread_sub PROGBITS        080d56b8 08d6b8 000004 00   A  0   0  4
  [14] .eh_frame         PROGBITS        080d56bc 08d6bc 0129d0 00   A  0   0  4
  [15] .gcc_except_table PROGBITS        080e808c 0a008c 0000b1 00   A  0   0  1
  [16] .tdata            PROGBITS        080e9f5c 0a0f5c 000010 00 WAT  0   0  4
  [17] .tbss             NOBITS          080e9f6c 0a0f6c 000018 00 WAT  0   0  4
  [18] .init_array       INIT_ARRAY      080e9f6c 0a0f6c 000008 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      080e9f74 0a0f74 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        080e9f7c 0a0f7c 000004 00  WA  0   0  4
  [21] .data.rel.ro      PROGBITS        080e9f80 0a0f80 000070 00  WA  0   0 32
  [22] .got              PROGBITS        080e9ff0 0a0ff0 000008 04  WA  0   0  4
  [23] .got.plt          PROGBITS        080ea000 0a1000 000044 04  WA  0   0  4
  [24] .data             PROGBITS        080ea060 0a1060 000f20 00  WA  0   0 32
  [25] .bss              NOBITS          080eaf80 0a1f80 000e0c 00  WA  0   0 32
  [26] __libc_freeres_pt NOBITS          080ebd8c 0a1f80 000018 00  WA  0   0  4
  [27] .comment          PROGBITS        00000000 0a1f80 000034 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 0b0ae0 00014c 00      0   0  1
  [29] .symtab           SYMTAB          00000000 0a1fb4 007e50 10     30 848  4
  [30] .strtab           STRTAB          00000000 0a9e04 006cdc 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

当然还有很多其他的如符号表、字符串表等等信息。

开始挖ELF的加载过程,怎么动起来的。
exec代码如下:

int Exec(int argc, char *argv[])
{
        int pid;
        /* fork another process */
        pid = fork();
        if (pid < 0)
        {
                /* error occurred */
                fprintf(stderr,"Fork Failed!");
                exit(-1);
        }
        else if (pid == 0)
        {
                /*       child process  */
        printf("This is Child Process!\n");
                execlp("/hello","hello",NULL);
        }
        else
        {
                /*      parent process   */
        printf("This is Parent Process!\n");
                /* parent will wait for the child to complete*/
                wait(NULL);
                printf("Child Complete!\n");
        }
}
  • 可以看到,代码中使用了exec这个系统调用,而且是在子进程中使用的。exec这个系统调用很有意思,和fork相反,exec调用一次,从不返回,因为他覆盖了调用进程。

搭建好执行环境:


设置了以下断点:


执行exec,和我们之前的系统调用一样,停在了sys_execve

  • 停在了getname处,可以看到,在查找/hello这个应用,而在我们简单的文件系统(我们的文件系统只有一个/根目录)下这个hello是存在的。

-- 注:有必要研究下这个系内核的文件系统是怎么实现的,在QEMU下用-initrd roofs.img的原理

  • 继续追踪下去,可以看到,执行了do_execv_common。停在了load_elf_binary处,这个函数很是关键,可以说,这个函数的实现部分和ELF的文件标准内的各种section、header等打交道,要想搞明白这个,还是先把elf文件的规约读懂。

  • 其实一句话说完,这段代码主要是围绕着elf文件的格式,来准备装载一个可执行程序所需要的各种环境。怎么说呢,应该说是这就是和ELF相呼应的地方。不过,若想搞明白,到底是怎样,两方面都要搞清楚。


  • 完了到了start_thread,我理解的是,start_kernel并没有真正的start,而是对内核的相关寄存器做了修改。

真正start的时候,还是在调度的时候,也即是把新的进程准备好,放到调度队列之后。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容