可执行程序的装载

曹朋辉
原创作品转载请注明出处
《Linux内核分析》MOOC课程

可执行文件的创建——预处理、编译和链接

shiyanlou:~/ $ cd Code                                                [9:27:05]
shiyanlou:Code/ $ vi hello.c                                          [9:27:14]
//预处理 -E
shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32                    [9:34:55]
shiyanlou:Code/ $ vi hello.cpp                                        [9:35:04]
//-x 指定文件类型
//将预处理的文件编译为汇编文件 -S
shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32      [9:35:21]
shiyanlou:Code/ $ vi hello.s                                          [9:35:28]
//将汇编文件编译为目标文件(二进制的)
shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32         [9:35:58]
shiyanlou:Code/ $ vi hello.o                                          [9:38:44]
//链接  hello为ELF格式的文件 以上语句调用共享库链接
shiyanlou:Code/ $ gcc -o hello hello.o -m32                           [9:39:37]
shiyanlou:Code/ $ vi hello                                            [9:39:44]
//调用静态库链接
shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static            [9:40:21]
shiyanlou:Code/ $ ls -l                                               [9:41:13]
-rwxrwxr-x 1 shiyanlou shiyanlou   7292  3\u6708 23 09:39 hello
-rw-rw-r-- 1 shiyanlou shiyanlou     64  3\u6708 23 09:30 hello.c
-rw-rw-r-- 1 shiyanlou shiyanlou  17302  3\u6708 23 09:35 hello.cpp
-rw-rw-r-- 1 shiyanlou shiyanlou   1020  3\u6708 23 09:38 hello.o
-rw-rw-r-- 1 shiyanlou shiyanlou    470  3\u6708 23 09:35 hello.s
-rwxrwxr-x 1 shiyanlou shiyanlou 733254  3\u6708 23 09:41 hello.static

静态链接和动态链接是怎么回事?
可执行文件的内部是怎样的?
ABI和目标文件什么关系?
命令行参数和环境变量是如何保存和传递的?
命令行参数和环境变量是如何进入新程序的堆栈的?

参数传递

![Upload Paste_Image.png failed. Please try again.]

目标文件及链接

ELF目标文件格式
ELF文件格式 -- (中文翻译版)

目标文件的格式

PE格式大多用在wondows上
ELF格式大多用在Linux上
ELF (Excutable and Linkble Format)

.o 可重定位

.o

a.out

a.out

.so

.so

查看ELF文件的头部

shiyanlou:Code/ $ readelf -h hello

readelf

查看该ELF文件依赖的共享库

shiyanlou:sharelib/ $ ldd main                                       [21:25:56]
    linux-gate.so.1 =>  (0xf774e000) # 这个是vdso - virtual DSO:dynamically shared object,并不存在这个共享库文件,它是内核的一部分,为了解决libc与新版本内核的系统调用不同步的问题,linux-gate.so.1里封装的系统调用与内核支持的系统调用完全匹配,因为它就是内核的一部分嘛。而libc里封装的系统调用与内核并不完全一致,因为它们各自都在版本更新。
    libshlibexample.so => /home/shiyanlou/LinuxKernel/sharelib/libshlibexample.so (0xf7749000)
    libdl.so.2 => /lib32/libdl.so.2 (0xf7734000)
    libc.so.6 => /lib32/libc.so.6 (0xf7588000)
    /lib/ld-linux.so.2 (0xf774f000)
shiyanlou:sharelib/ $ ldd /lib32/libc.so.6                         [21:37:00]
    /lib/ld-linux.so.2 (0xf779e000)
    linux-gate.so.1 =>  (0xf779d000)
# readelf -d 也可以看依赖的so文件
shiyanlou:sharelib/ $ readelf -d main                              [21:28:04]
Dynamic section at offset 0xf04 contains 26 entries:
 0x00000001 (NEEDED)                     共享库:[libshlibexample.so]
 0x00000001 (NEEDED)                     共享库:[libdl.so.2]
 0x00000001 (NEEDED)                     共享库:[libc.so.6]
 0x0000000c (INIT)                       0x80484f0
 0x0000000d (FINI)                       0x8048804
 0x00000019 (INIT_ARRAY)                 0x8049ef8

命令行参数和shell环境,一般我们执行一个程序的Shell环境,我们的实验直接使用execve系统调用。
$ ls -l /usr/bin 列出/usr/bin下的目录信息
Shell本身不限制命令行参数的个数,�命令行参数的个数受限于命令自身
例如,int main(int argc, char *argv[])
又如, int main(int argc, char *argv[], char envp[])
Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
库函数exec
都是execve的封装例程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(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   */
        execlp("/bin/ls","ls",NULL);
    } 
    else 
    {  
        /*     parent process  */
        /* parent will wait for the child to complete*/
        wait(NULL);
        printf("Child Complete!");
        exit(0);
    }
}

命令行参数和环境串都放在用户态堆栈中

用户态堆栈

在linux中一个程序是如何加载运行的

在shell中输入一个程序的名称时,shell会先fork一个子进程,然后在子进程中调用execlp函数来拉起我们执行的程序,

exec系统调用

首先,exec会调用sys_execve,然后调用do_execve,再调用do_execve_common,这个函数会把函数参数和系统环境传进来进行相应的处理。然后调用exec_binprm来执行相应的程序。而exec_binprm又会调用search_binary_handler,这个函数会调用各种不同的格式来识别相应的文件,直到识别为止,比如linux中可执行文件为ELF,它就会识别出elf文件。

在sys_execve处设置断点

sys_execve

retval = fmt->load_binary(bprm)把对应的文件以对应的格式加载到内存里面。由于Linux是elf格式,故会执行对应的load_elf_binary,然后在这个函数里面有一个函数start_thread,这个函数会复制内核堆栈,同时会设置新的进程的执行位置,即会设置新的eip,使eip指向新程序的入口位置。

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

推荐阅读更多精彩内容