Linux内核如何装载和启动一个可执行程序

可执行文件的创建

  • 预处理阶段
    这一过程,主要针对#include和#define进行处理,具体过程如下:对于cpp文件中经常会出现#include来包含某个头文件,在进行预处理之后,所有的#include命令都将替换成该头文件中的详细内容,如果该头文件中还包含另外的头文件,采用同样的方法进行递归处理。同样#define亦是如此,对用它进行宏定义的字符进行替换,这里就是简单的替换。所以整个预处理过程就是进行简单的替换。
    c
    #include<stdio.h>
    void main(void)
    {
    printf("hello world\n");
    return 0;
    }

    对hello.c文件进行预处理:
    gcc -E hello.c -o hello.i
    使用vim hello.i,部分代码如下
# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
.....
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
....
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 943 "/usr/include/stdio.h" 3 4
# 2 "hello.c" 2
int main(void)
{
    printf("hello world\n");
    return 0;
}
  • 编译阶段
    编译器进行词法分析、语法分析,把源代码翻译为汇编语言
    gcc -S hello.i -o hello.s
 .file   "hello.c"
        .section        .rodata
.LC0:
        .string "hello world"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $.LC0, %edi
        call    puts
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
 .size   main, .-main
        .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
        .section        .note.GNU-stack,"",@progbits
  • 汇编阶段
    汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码.
    gcc –c hello.s –o hello.o
    使用vim hello.o
^@UH<89>å¿^@^@^@^@è^@^@^@^@¸^@^@^@^@]Ãhello world^@^@GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4^@^@^@^@^T^@^@^@^@^@^@^@^AzR^@^Ax^P^A^[^L^G^H<90>^A^@^@^\^@^@^@^\^@^@^@^@^@^@^@^U^@^@^@^@A^N^P<86>^BC^M^FP^L^G^H^@^@^@^@.symtab^@.strtab^@.shstrtab^@.rela.text^@.data^@.bss^@.rodata^@.comment^@.note.GNU-stack^@.rela.eh_frame^@
  • 链接阶段
    通过链接器将一个个目标文件(或许还会有库文件)链接在一起生成一个完整的可执行程序。链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
    gcc hello.o -o hello
    hello

文件的格式

  • 一个可重定位(relocatable)文件保存着代码和适当的数据,用来和其他的
    object文件一起来创建一个可执行文件或者是一个共享文件。
  • 一个可执行(executable)文件保存着一个用来执行的程序;该文件指出了
    exec(BA_OS)如何来创建程序进程映象。
  • 一个共享object文件保存着代码和合适的数据,用来被下面的两个链接器
    链接。第一个是连接编辑器[请参看ld(SD_CMD)],可以和其他的可重定位和
    共享object文件来创建其他的object。第二个是动态链接器,联合一个
    可执行文件和其他的共享object文件来创建一个进程映象。

execve系统调用

do_execve:

1549int do_execve(struct filename *filename,
1550    const char __user *const __user *__argv,
1551    const char __user *const __user *__envp)
1552{
1553    struct user_arg_ptr argv = { .ptr.native = __argv };
1554    struct user_arg_ptr envp = { .ptr.native = __envp };
1555    return do_execve_common(filename, argv, envp);
1556}

do_execve_common

1430 static int do_execve_common(struct filename *filename,
1431                struct user_arg_ptr argv,
1432                struct user_arg_ptr envp)
1433{
1434    struct linux_binprm *bprm;
1435    struct file *file;
....
1458    retval = unshare_files(&displaced);
....
1467    retval = prepare_bprm_creds(bprm);
....
1474    file = do_open_exec(filename);
....
1484    retval = bprm_mm_init(bprm);
....

1504    bprm->exec = bprm->p;
1505    retval = copy_strings(bprm->envc, envp, bprm);
1506    if (retval < 0)
1507        goto out;
1508
1509    retval = copy_strings(bprm->argc, argv, bprm);
1510    if (retval < 0)
1511        goto out;
1512
1513    retval = exec_binprm(bprm);
....
1547}

exec_binprm:

1405static int exec_binprm(struct linux_binprm *bprm)
1406{
1407    pid_t old_pid, old_vpid;
1408    int ret;
1409
1410    /* Need to fetch pid before load_binary changes it */
1411    old_pid = current->pid;
1412    rcu_read_lock();
1413    old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
1414    rcu_read_unlock();
1415
1416    ret = search_binary_handler(bprm);
1417    if (ret >= 0) {
1418        audit_bprm(bprm);
1419        trace_sched_process_exec(current, old_pid, bprm);
1420        ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
1421        proc_exec_connector(current);
1422    }
1423
1424    return ret;
1425}

search_binary_headler:

1352int search_binary_handler(struct linux_binprm *bprm)
1353{
1355    struct linux_binfmt *fmt;
1369    list_for_each_entry(fmt, &formats, lh) {
1370        if (!try_module_get(fmt->module))
1371            continue;
1372        read_unlock(&binfmt_lock);
1373        bprm->recursion_depth++;
1374        retval = fmt->load_binary(bprm);
1375        read_lock(&binfmt_lock);
1376        put_binfmt(fmt);
1377        bprm->recursion_depth--;
1378        if (retval < 0 && !bprm->mm) {
1379            /* we got to flush_old_exec() and failed after it */
1380            read_unlock(&binfmt_lock);
1381            force_sigsegv(SIGSEGV, current);
1382            return retval;
1383        }
1384        if (retval != -ENOEXEC || !bprm->file) {
1385            read_unlock(&binfmt_lock);
1386            return retval;
1387        }
1388    }

load_elf_binary:

571 static int load_elf_binary(struct linux_binprm *bprm)
572{
.....
975 start_thread(regs, elf_entry, bprm->p);
992}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值