精华内容
下载资源
问答
  • 如何实现在Windows上运行Linux程序,附示例代码   微软在去年发布了Bash On Windows, 这项技术允许在Windows上运行Linux程序, 我相信已经有很多文章解释过Bash On Windows的原理,而今天的这篇文章将会讲解如何自己...

    如何实现在Windows上运行Linux程序,附示例代码

     

    微软在去年发布了Bash On Windows, 这项技术允许在Windows上运行Linux程序, 我相信已经有很多文章解释过Bash On Windows的原理,
    而今天的这篇文章将会讲解如何自己实现一个简单的原生Linux程序运行器, 这个运行器在用户层实现, 原理和Bash On Windows不完全一样,比较接近Linux上的Wine.

    示例程序完整的代码在github上, 地址是 https://github.com/303248153/HelloElfLoader

    初步了解ELF格式

    首先让我们先了解什么是原生Linux程序, 以下说明摘自维基百科

    In computing, the Executable and Linkable Format (ELF, formerly named Extensible Linking Format), is a common standard file format for executable files, object code, shared libraries, and core dumps. First published in the specification for the application binary interface (ABI) of the Unix operating system version named System V Release 4 (SVR4),[2] and later in the Tool Interface Standard,[1] it was quickly accepted among different vendors of Unix systems. In 1999, it was chosen as the standard binary file format for Unix and Unix-like systems on x86 processors by the 86open project.
    
    By design, ELF is flexible, extensible, and cross-platform, not bound to any given central processing unit (CPU) or instruction set architecture. This has allowed it to be adopted by many different operating systems on many different hardware platforms.

    Linux的可执行文件格式采用了ELF格式, 而Windows采用了PE格式, 也就是我们经常使用的exe文件的格式.

    ELF格式的结构如下

    大致上可以分为这些部分

    • ELF头,在文件的最开头,储存了类型和版本等信息
    • 程序头, 供程序运行时解释器(interpreter)使用
    • 节头, 供程序编译时链接器(linker)使用, 运行时不需要读节头
    • 节内容, 不同的节作用都不一样
      • .text 代码节,保存了主要的程序代码
      • .rodata 保存了只读的数据,例如字符串(const char*)
      • .data 保存了可读写的数据,例如全局变量
      • 还有其他各种各样的节

    让我们来实际看一下Linux可执行程序的样子
    以下的编译环境是Ubuntu 16.04 x64 + gcc 5.4.0, 编译环境不一样可能会得出不同的结果

    首先创建hello.c,写入以下的代码

    #include <stdio.h>
    
    int max(int x, int y) {
        return x > y ? x : y;
    }
    
    int main() {
        printf("max is %d\n", max(123, 321));
        printf("test many arguments %d %d %d %s %s %s %s %s %s\n", 1, 2, 3, "a", "b", "c", "d", "e", "f");
        return 100;
    }

    然后使用gcc编译这份代码

    gcc hello.c

    编译完成后你可以看到hello.c旁边多了一个a.out, 这就是linux的可执行文件了, 现在可以在linux上运行它

    ./a.out

    你可以看到以下输出

    max is 321
    test many arguments 1 2 3 a b c d e f

    我们来看看a.out包含了什么,解析ELF文件可以使用readelf命令

    readelf -a ./a.out

    可以看到输出了以下的信息

    ELF 头:
      Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
      类别:                              ELF64
      数据:                              2 补码,小端序 (little endian)
      版本:                              1 (current)
      OS/ABI:                            UNIX - System V
      ABI 版本:                          0
      类型:                              EXEC (可执行文件)
      系统架构:                          Advanced Micro Devices X86-64
      版本:                              0x1
      入口点地址:               0x400430
      程序头起点:          64 (bytes into file)
      Start of section headers:          6648 (bytes into file)
      标志:             0x0
      本头的大小:       64 (字节)
      程序头大小:       56 (字节)
      Number of program headers:         9
      节头大小:         64 (字节)
      节头数量:         31
      字符串表索引节头: 28
    
    节头:
      [号] 名称              类型             地址              偏移量
           大小              全体大小          旗标   链接   信息   对齐
      [ 0]                   NULL             0000000000000000  00000000
           0000000000000000  0000000000000000           0     0     0
      [ 1] .interp           PROGBITS         0000000000400238  00000238
           000000000000001c  0000000000000000   A       0     0     1
      [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
           0000000000000020  0000000000000000   A       0     0     4
      [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
           0000000000000024  0000000000000000   A       0     0     4
      [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
           000000000000001c  0000000000000000   A       5     0     8
      [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
           0000000000000060  0000000000000018   A       6     1     8
      [ 6] .dynstr           STRTAB           0000000000400318  00000318
           000000000000003f  0000000000000000   A       0     0     1
      [ 7] .gnu.version      VERSYM           0000000000400358  00000358
           0000000000000008  0000000000000002   A       5     0     2
      [ 8] .gnu.version_r    VERNEED          0000000000400360  00000360
           0000000000000020  0000000000000000   A       6     1     8
      [ 9] .rela.dyn         RELA             0000000000400380  00000380
           0000000000000018  0000000000000018   A       5     0     8
      [10] .rela.plt         RELA             0000000000400398  00000398
           0000000000000030  0000000000000018  AI       5    24     8
      [11] .init             PROGBITS         00000000004003c8  000003c8
           000000000000001a  0000000000000000  AX       0     0     4
      [12] .plt              PROGBITS         00000000004003f0  000003f0
           0000000000000030  0000000000000010  AX       0     0     16
      [13] .plt.got          PROGBITS         0000000000400420  00000420
           0000000000000008  0000000000000000  AX       0     0     8
      [14] .text             PROGBITS         0000000000400430  00000430
           00000000000001f2  0000000000000000  AX       0     0     16
      [15] .fini             PROGBITS         0000000000400624  00000624
           0000000000000009  0000000000000000  AX       0     0     4
      [16] .rodata           PROGBITS         0000000000400630  00000630
           0000000000000050  0000000000000000   A       0     0     8
      [17] .eh_frame_hdr     PROGBITS         0000000000400680  00000680
           000000000000003c  0000000000000000   A       0     0     4
      [18] .eh_frame         PROGBITS         00000000004006c0  000006c0
           0000000000000114  0000000000000000   A       0     0     8
      [19] .init_array       INIT_ARRAY       0000000000600e10  00000e10
           0000000000000008  0000000000000000  WA       0     0     8
      [20] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
           0000000000000008  0000000000000000  WA       0     0     8
      [21] .jcr              PROGBITS         0000000000600e20  00000e20
           0000000000000008  0000000000000000  WA       0     0     8
      [22] .dynamic          DYNAMIC          0000000000600e28  00000e28
           00000000000001d0  0000000000000010  WA       6     0     8
      [23] .got              PROGBITS         0000000000600ff8  00000ff8
           0000000000000008  0000000000000008  WA       0     0     8
      [24] .got.plt          PROGBITS         0000000000601000  00001000
           0000000000000028  0000000000000008  WA       0     0     8
      [25] .data             PROGBITS         0000000000601028  00001028
           0000000000000010  0000000000000000  WA       0     0     8
      [26] .bss              NOBITS           0000000000601038  00001038
           0000000000000008  0000000000000000  WA       0     0     1
      [27] .comment          PROGBITS         0000000000000000  00001038
           0000000000000034  0000000000000001  MS       0     0     1
      [28] .shstrtab         STRTAB           0000000000000000  000018ea
           000000000000010c  0000000000000000           0     0     1
      [29] .symtab           SYMTAB           0000000000000000  00001070
           0000000000000660  0000000000000018          30    47     8
      [30] .strtab           STRTAB           0000000000000000  000016d0
           000000000000021a  0000000000000000           0     0     1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
      I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
      O (extra OS processing required) o (OS specific), p (processor specific)
    
    There are no section groups in this file.
    
    程序头:
      Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
      PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                     0x00000000000001f8 0x00000000000001f8  R E    8
      INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                     0x000000000000001c 0x000000000000001c  R      1
          [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
      LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                     0x00000000000007d4 0x00000000000007d4  R E    200000
      LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                     0x0000000000000228 0x0000000000000230  RW     200000
      DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e28
                     0x00000000000001d0 0x00000000000001d0  RW     8
      NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                     0x0000000000000044 0x0000000000000044  R      4
      GNU_EH_FRAME   0x0000000000000680 0x0000000000400680 0x0000000000400680
                     0x000000000000003c 0x000000000000003c  R      4
      GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                     0x0000000000000000 0x0000000000000000  RW     10
      GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                     0x00000000000001f0 0x00000000000001f0  R      1
    
     Section to Segment mapping:
      段节...
       00     
       01     .interp 
       02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 
       03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
       04     .dynamic 
       05     .note.ABI-tag .note.gnu.build-id 
       06     .eh_frame_hdr 
       07     
       08     .init_array .fini_array .jcr .dynamic .got 
    
    Dynamic section at offset 0xe28 contains 24 entries:
      标记        类型                         名称/值
     0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
     0x000000000000000c (INIT)               0x4003c8
     0x000000000000000d (FINI)               0x400624
     0x0000000000000019 (INIT_ARRAY)         0x600e10
     0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
     0x000000000000001a (FINI_ARRAY)         0x600e18
     0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
     0x000000006ffffef5 (GNU_HASH)           0x400298
     0x0000000000000005 (STRTAB)             0x400318
     0x0000000000000006 (SYMTAB)             0x4002b8
     0x000000000000000a (STRSZ)              63 (bytes)
     0x000000000000000b (SYMENT)             24 (bytes)
     0x0000000000000015 (DEBUG)              0x0
     0x0000000000000003 (PLTGOT)             0x601000
     0x0000000000000002 (PLTRELSZ)           48 (bytes)
     0x0000000000000014 (PLTREL)             RELA
     0x0000000000000017 (JMPREL)             0x400398
     0x0000000000000007 (RELA)               0x400380
     0x0000000000000008 (RELASZ)             24 (bytes)
     0x0000000000000009 (RELAENT)            24 (bytes)
     0x000000006ffffffe (VERNEED)            0x400360
     0x000000006fffffff (VERNEEDNUM)         1
     0x000000006ffffff0 (VERSYM)             0x400358
     0x0000000000000000 (NULL)               0x0
    
    重定位节 '.rela.dyn' 位于偏移量 0x380 含有 1 个条目:
      偏移量          信息           类型           符号值        符号名称 + 加数
    000000600ff8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
    
    重定位节 '.rela.plt' 位于偏移量 0x398 含有 2 个条目:
      偏移量          信息           类型           符号值        符号名称 + 加数
    000000601018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
    000000601020  000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
    
    The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
    
    Symbol table '.dynsym' contains 4 entries:
       Num:    Value          Size Type    Bind   Vis      Ndx Name
         0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
         2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
         3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    
    Symbol table '.symtab' contains 68 entries:
       Num:    Value          Size Type    Bind   Vis      Ndx Name
         0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 0000000000400238     0 SECTION LOCAL  DEFAULT    1 
         2: 0000000000400254     0 SECTION LOCAL  DEFAULT    2 
         3: 0000000000400274     0 SECTION LOCAL  DEFAULT    3 
         4: 0000000000400298     0 SECTION LOCAL  DEFAULT    4 
         5: 00000000004002b8     0 SECTION LOCAL  DEFAULT    5 
         6: 0000000000400318     0 SECTION LOCAL  DEFAULT    6 
         7: 0000000000400358     0 SECTION LOCAL  DEFAULT    7 
         8: 0000000000400360     0 SECTION LOCAL  DEFAULT    8 
         9: 0000000000400380     0 SECTION LOCAL  DEFAULT    9 
        10: 0000000000400398     0 SECTION LOCAL  DEFAULT   10 
        11: 00000000004003c8     0 SECTION LOCAL  DEFAULT   11 
        12: 00000000004003f0     0 SECTION LOCAL  DEFAULT   12 
        13: 0000000000400420     0 SECTION LOCAL  DEFAULT   13 
        14: 0000000000400430     0 SECTION LOCAL  DEFAULT   14 
        15: 0000000000400624     0 SECTION LOCAL  DEFAULT   15 
        16: 0000000000400630     0 SECTION LOCAL  DEFAULT   16 
        17: 0000000000400680     0 SECTION LOCAL  DEFAULT   17 
        18: 00000000004006c0     0 SECTION LOCAL  DEFAULT   18 
        19: 0000000000600e10     0 SECTION LOCAL  DEFAULT   19 
        20: 0000000000600e18     0 SECTION LOCAL  DEFAULT   20 
        21: 0000000000600e20     0 SECTION LOCAL  DEFAULT   21 
        22: 0000000000600e28     0 SECTION LOCAL  DEFAULT   22 
        23: 0000000000600ff8     0 SECTION LOCAL  DEFAULT   23 
        24: 0000000000601000     0 SECTION LOCAL  DEFAULT   24 
        25: 0000000000601028     0 SECTION LOCAL  DEFAULT   25 
        26: 0000000000601038     0 SECTION LOCAL  DEFAULT   26 
        27: 0000000000000000     0 SECTION LOCAL  DEFAULT   27 
        28: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
        29: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   21 __JCR_LIST__
        30: 0000000000400460     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones
        31: 00000000004004a0     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones
        32: 00000000004004e0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
        33: 0000000000601038     1 OBJECT  LOCAL  DEFAULT   26 completed.7585
        34: 0000000000600e18     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtors_aux_fin
        35: 0000000000400500     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
        36: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_init_array_
        37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
        38: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
        39: 00000000004007d0     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
        40: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   21 __JCR_END__
        41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 
        42: 0000000000600e18     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_end
        43: 0000000000600e28     0 OBJECT  LOCAL  DEFAULT   22 _DYNAMIC
        44: 0000000000600e10     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start
        45: 0000000000400680     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR
        46: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_
        47: 0000000000400620     2 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
        48: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
        49: 0000000000601028     0 NOTYPE  WEAK   DEFAULT   25 data_start
        50: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 _edata
        51: 0000000000400624     0 FUNC    GLOBAL DEFAULT   15 _fini
        52: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
        53: 0000000000400526    22 FUNC    GLOBAL DEFAULT   14 max
        54: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
        55: 0000000000601028     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
        56: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
        57: 0000000000601030     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
        58: 0000000000400630     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
        59: 00000000004005b0   101 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
        60: 0000000000601040     0 NOTYPE  GLOBAL DEFAULT   26 _end
        61: 0000000000400430    42 FUNC    GLOBAL DEFAULT   14 _start
        62: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start
        63: 000000000040053c   109 FUNC    GLOBAL DEFAULT   14 main
        64: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
        65: 0000000000601038     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__
        66: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
        67: 00000000004003c8     0 FUNC    GLOBAL DEFAULT   11 _init
    
    Version symbols section '.gnu.version' contains 4 entries:
     地址: 0000000000400358  Offset: 0x000358  Link: 5 (.dynsym)
      000:   0 (*本地*)       2 (GLIBC_2.2.5)   2 (GLIBC_2.2.5)   0 (*本地*)    
    
    Version needs section '.gnu.version_r' contains 1 entries:
     地址:0x0000000000400360  Offset: 0x000360  Link: 6 (.dynstr)
      000000: 版本: 1  文件:libc.so.6  计数:1
      0x0010:名称:GLIBC_2.2.5  标志:无  版本:2
    
    Displaying notes found at file offset 0x00000254 with length 0x00000020:
      Owner                 Data size   Description
      GNU                  0x00000010   NT_GNU_ABI_TAG (ABI version tag)
        OS: Linux, ABI: 2.6.32
    
    Displaying notes found at file offset 0x00000274 with length 0x00000024:
      Owner                 Data size   Description
      GNU                  0x00000014   NT_GNU_BUILD_ID (unique build ID bitstring)
        Build ID: debd3d7912be860a432b5c685a6cff7fd9418528

    从上面的信息中我们可以知道这个文件的类型是ELF64, 也就是64位的可执行程序, 并且有9个程序头和31个节头, 各个节的作用大家可以在网上找到资料, 这篇文章中只涉及到以下的节

    • .init 程序初始化的代码
    • .rela.dyn 需要重定位的变量列表
    • .rela.plt 需要重定位的函数列表
    • .plt 调用动态链接函数的代码
    • .text 保存了主要的程序代码
    • .init 保存了程序的初始化代码, 用于初始化全局变量等
    • .fini 保存了程序的终止代码, 用于析构全局变量等
    • .rodata 保存了只读的数据,例如字符串(const char*)
    • .data 保存了可读写的数据,例如全局变量
    • .dynsym 动态链接的符号表
    • .dynstr 动态链接的符号名称字符串
    • .dynamic 动态链接所需要的信息,供程序运行时使用(不需要访问节头)

    什么是动态链接

    上面的程序中调用了printf函数, 然而这个函数的实现并不在./a.out中, 那么printf函数在哪里, 又是怎么被调用的?

    printf函数的实现在glibc库中, 也就是/lib/x86_64-linux-gnu/libc.so.6中, 在执行./a.out的时候会在glibc库中找到这个函数并进行调用, 我们来看看这段代码

    执行以下命令反编译./a.out

    objdump -c -S ./a.out

    我们可以看到以下的代码

    00000000004003f0 <printf@plt-0x10>:
      4003f0:   ff 35 12 0c 20 00       pushq  0x200c12(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
      4003f6:   ff 25 14 0c 20 00       jmpq   *0x200c14(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
      4003fc:   0f 1f 40 00             nopl   0x0(%rax)
    
    0000000000400400 <printf@plt>:
      400400:   ff 25 12 0c 20 00       jmpq   *0x200c12(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
      400406:   68 00 00 00 00          pushq  $0x0
      40040b:   e9 e0 ff ff ff          jmpq   4003f0 <_init+0x28>
    
    000000000040053c <main>:
      40053c:   55                      push   %rbp
      40053d:   48 89 e5                mov    %rsp,%rbp
      400540:   be 41 01 00 00          mov    $0x141,%esi
      400545:   bf 7b 00 00 00          mov    $0x7b,%edi
      40054a:   e8 d7 ff ff ff          callq  400526 <max>
      40054f:   89 c6                   mov    %eax,%esi
      400551:   bf 38 06 40 00          mov    $0x400638,%edi
      400556:   b8 00 00 00 00          mov    $0x0,%eax
      40055b:   e8 a0 fe ff ff          callq  400400 <printf@plt>

    在这一段代码中,我们可以看到调用printf会首先调用0x400400printf@plt
    printf@plt会负责在运行时找到实际的printf函数并跳转到该函数
    在这里实际的printf函数会保存在0x400406 + 0x200c12 = 0x601018

    需要注意的是0x601018一开始并不会指向实际的printf函数,而是会指向0x400406, 为什么会这样? 因为Linux的可执行程序为了考虑性能,不会在一开始就解决所有动态连接的函数,而是选择了延迟解决.
    在上面第一次jmpq *0x200c12(%rip)会跳转到下一条指令0x400406, 又会继续跳转到0x4003f0, 再跳转到0x601010指向的地址, 0x601010指向的地址就是延迟解决的实现, 第一次延迟解决成功后, 0x601018就会指向实际的printf, 以后调用就会直接跳转到实际的printf上.

    程序入口点

    Linux程序运行首先会从_start函数开始, 上面readelf中的入口点地址0x400430就是_start函数的地址,

    0000000000400430 <_start>:
      400430:   31 ed                   xor    %ebp,%ebp
      400432:   49 89 d1                mov    %rdx,%r9
      400435:   5e                      pop    %rsi
      400436:   48 89 e2                mov    %rsp,%rdx
      400439:   48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
      40043d:   50                      push   %rax
      40043e:   54                      push   %rsp
      40043f:   49 c7 c0 20 06 40 00    mov    $0x400620,%r8
      400446:   48 c7 c1 b0 05 40 00    mov    $0x4005b0,%rcx
      40044d:   48 c7 c7 3c 05 40 00    mov    $0x40053c,%rdi
      400454:   e8 b7 ff ff ff          callq  400410 <__libc_start_main@plt>
      400459:   f4                      hlt    
      40045a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

    接下来_start函数会调用__libc_start_main函数, __libc_start_main是libc库中定义的初始化函数, 负责初始化全局变量和调用main函数等工作.

    __libc_start_main函数还负责设置返回值和退出进程, 可以看到上面调用__libc_start_main后的指令是hlt, 这个指令永远不会被执行.

    实现Linux程序运行器

    在拥有以上的知识后我们可以先构想以下的运行器需要做什么.

    因为x64的Windows和Linux程序使用的cpu指令集都是一样的,我们可以直接执行汇编而不需要一个指令模拟器,
    而且这次我打算在用户层实现, 所以不能像Bash On Windows一样模拟syscall, 这个运行器会像下图一样模拟libc库的函数

    这样运行器需要做的事情有:

    • 解析ELF文件
    • 加载程序代码到指定的内存地址
    • 加载数据到指定的内存地址
    • 提供动态链接的函数实现
    • 执行加载的程序代码

    这些工作会在以下的示例程序中一一实现, 完整的源代码可以看文章顶部的链接

    首先我们需要把ELF文件格式对应的代码从binutils中复制过来, 它包含了ELF头, 程序头和相关的数据结构, 里面用unsigned char[]是为了防止alignment, 这样结构体可以直接从文件内容中转换过来

    ELFDefine.h:

    #pragma once
    
    namespace HelloElfLoader {
        // 以下内容复制自
        // https://github.com/aeste/binutils/blob/develop/elfcpp/elfcpp.h
        // https://github.com/aeste/binutils/blob/develop/include/elf/external.h
    
        // e_ident中各项的偏移值
        const int EI_MAG0 = 0;
        const int EI_MAG1 = 1;
        const int EI_MAG2 = 2;
        const int EI_MAG3 = 3;
        const int EI_CLASS = 4;
        const int EI_DATA = 5;
        const int EI_VERSION = 6;
        const int EI_OSABI = 7;
        const int EI_ABIVERSION = 8;
        const int EI_PAD = 9;
        const int EI_NIDENT = 16;
    
        // ELF文件类型
        enum {
            ELFCLASSNONE = 0,
            ELFCLASS32 = 1,
            ELFCLASS64 = 2
        };
    
        // ByteOrder
        enum {
            ELFDATANONE = 0,
            ELFDATA2LSB = 1,
            ELFDATA2MSB = 2
        };
    
        // 程序头类型
        enum PT
        {
            PT_NULL = 0,
            PT_LOAD = 1,
            PT_DYNAMIC = 2,
            PT_INTERP = 3,
            PT_NOTE = 4,
            PT_SHLIB = 5,
            PT_PHDR = 6,
            PT_TLS = 7,
            PT_LOOS = 0x60000000,
            PT_HIOS = 0x6fffffff,
            PT_LOPROC = 0x70000000,
            PT_HIPROC = 0x7fffffff,
            // The remaining values are not in the standard.
            // Frame unwind information.
            PT_GNU_EH_FRAME = 0x6474e550,
            PT_SUNW_EH_FRAME = 0x6474e550,
            // Stack flags.
            PT_GNU_STACK = 0x6474e551,
            // Read only after relocation.
            PT_GNU_RELRO = 0x6474e552,
            // Platform architecture compatibility information
            PT_ARM_ARCHEXT = 0x70000000,
            // Exception unwind tables
            PT_ARM_EXIDX = 0x70000001
        };
    
        // 动态节类型
        enum DT
        {
            DT_NULL = 0,
            DT_NEEDED = 1,
            DT_PLTRELSZ = 2,
            DT_PLTGOT = 3,
            DT_HASH = 4,
            DT_STRTAB = 5,
            DT_SYMTAB = 6,
            DT_RELA = 7,
            DT_RELASZ = 8,
            DT_RELAENT = 9,
            DT_STRSZ = 10,
            DT_SYMENT = 11,
            DT_INIT = 12,
            DT_FINI = 13,
            DT_SONAME = 14,
            DT_RPATH = 15,
            DT_SYMBOLIC = 16,
            DT_REL = 17,
            DT_RELSZ = 18,
            DT_RELENT = 19,
            DT_PLTREL = 20,
            DT_DEBUG = 21,
            DT_TEXTREL = 22,
            DT_JMPREL = 23,
            DT_BIND_NOW = 24,
            DT_INIT_ARRAY = 25,
            DT_FINI_ARRAY = 26,
            DT_INIT_ARRAYSZ = 27,
            DT_FINI_ARRAYSZ = 28,
            DT_RUNPATH = 29,
            DT_FLAGS = 30,
    
            // This is used to mark a range of dynamic tags.  It is not really
            // a tag value.
            DT_ENCODING = 32,
    
            DT_PREINIT_ARRAY = 32,
            DT_PREINIT_ARRAYSZ = 33,
            DT_LOOS = 0x6000000d,
            DT_HIOS = 0x6ffff000,
            DT_LOPROC = 0x70000000,
            DT_HIPROC = 0x7fffffff,
    
            // The remaining values are extensions used by GNU or Solaris.
            DT_VALRNGLO = 0x6ffffd00,
            DT_GNU_PRELINKED = 0x6ffffdf5,
            DT_GNU_CONFLICTSZ = 0x6ffffdf6,
            DT_GNU_LIBLISTSZ = 0x6ffffdf7,
            DT_CHECKSUM = 0x6ffffdf8,
            DT_PLTPADSZ = 0x6ffffdf9,
            DT_MOVEENT = 0x6ffffdfa,
            DT_MOVESZ = 0x6ffffdfb,
            DT_FEATURE = 0x6ffffdfc,
            DT_POSFLAG_1 = 0x6ffffdfd,
            DT_SYMINSZ = 0x6ffffdfe,
            DT_SYMINENT = 0x6ffffdff,
            DT_VALRNGHI = 0x6ffffdff,
    
            DT_ADDRRNGLO = 0x6ffffe00,
            DT_GNU_HASH = 0x6ffffef5,
            DT_TLSDESC_PLT = 0x6ffffef6,
            DT_TLSDESC_GOT = 0x6ffffef7,
            DT_GNU_CONFLICT = 0x6ffffef8,
            DT_GNU_LIBLIST = 0x6ffffef9,
            DT_CONFIG = 0x6ffffefa,
            DT_DEPAUDIT = 0x6ffffefb,
            DT_AUDIT = 0x6ffffefc,
            DT_PLTPAD = 0x6ffffefd,
            DT_MOVETAB = 0x6ffffefe,
            DT_SYMINFO = 0x6ffffeff,
            DT_ADDRRNGHI = 0x6ffffeff,
    
            DT_RELACOUNT = 0x6ffffff9,
            DT_RELCOUNT = 0x6ffffffa,
            DT_FLAGS_1 = 0x6ffffffb,
            DT_VERDEF = 0x6ffffffc,
            DT_VERDEFNUM = 0x6ffffffd,
            DT_VERNEED = 0x6ffffffe,
            DT_VERNEEDNUM = 0x6fffffff,
    
            DT_VERSYM = 0x6ffffff0,
    
            // Specify the value of _GLOBAL_OFFSET_TABLE_.
            DT_PPC_GOT = 0x70000000,
    
            // Specify the start of the .glink section.
            DT_PPC64_GLINK = 0x70000000,
    
            // Specify the start and size of the .opd section.
            DT_PPC64_OPD = 0x70000001,
            DT_PPC64_OPDSZ = 0x70000002,
    
            // The index of an STT_SPARC_REGISTER symbol within the DT_SYMTAB
            // symbol table.  One dynamic entry exists for every STT_SPARC_REGISTER
            // symbol in the symbol table.
            DT_SPARC_REGISTER = 0x70000001,
    
            DT_AUXILIARY = 0x7ffffffd,
            DT_USED = 0x7ffffffe,
            DT_FILTER = 0x7fffffff
        };;
    
        // ELF头的定义
        typedef struct {
            unsigned char   e_ident[16];        /* ELF "magic number" */
            unsigned char   e_type[2];      /* Identifies object file type */
            unsigned char   e_machine[2];       
    展开全文
  • Atratus 项目可以让你在 Windows运行 Linux 的二进制执行文件。它包含 ELF 二进制加载器、libc 实现和一个系统调用转换器。目前还处于 alpha 前阶段。 Atratus 0.5 现在可运行多款 Linux 下的控制台游戏,包括 ...

    Atratus 项目可以让你在 Windows 下运行 Linux 的二进制执行文件。它包含 ELF 二进制加载器、libc 实现和一个系统调用转换器。目前还处于 alpha 前阶段。

    Atratus 0.5 现在可运行多款 Linux 下的控制台游戏,包括 robotfindskitten, robots, hangman, 和 snake. 大大提升了  vt100 终端支持,而 IPv4 的 socket 支持正在进行中。


    <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
    展开全文
  • Lina是一个开发中的项目,可以让Windows或者MacOS用户在他们的电脑上运行Linux程序,他还支持仅仅使用鼠标点击就安装Linux软件,而不用从源码包编译,非常值得大家关注,内含相关网站,技术白皮书,该产品还在开发中...
  • Windows 运行 Linux程序

    2019-09-18 04:05:07
    ForeignLINUX详细介绍 Foreign LINUX 项目旨在让用户能在Windows上不做任何修改的...自由软件社区有一个类似的项目叫Cygwin, 但需要重新编译才能将Linux或BSD上的软件运行Windows上。Foreign LINUX绕过了这一对...

    Foreign LINUX 详细介绍

    Foreign LINUX 项目旨在让用户能在Windows上不做任何修改的跑Linux二进制文件。自由软件社区有一个类似的项目叫Cygwin, 但需要重新编译才能将Linux或BSD上的软件运行在Windows上。Foreign LINUX绕过了这一对普通用户来说过于困难的过程,它是一个动态二进制翻译器和Linux系统调用接口模拟器,目前它处于早期开发阶段,能运行的 Linux工具包括bash、vim、nano、python、gcc等。
    Windows 运行 Linux程序Windows 运行 Linux程序

    原文来自:https://www.oschina.net/p/foreign-linux

    转载于:https://my.oschina.net/linuxprobe16/blog/1604889

    展开全文
  • Windows上运行Linux

    2020-04-06 10:28:39
    之前了解过一些适用于linux的Windows子系统,最近又听人提起,于是在自己的Windows 10专业版上安装了一个Ubuntu。运行起来还真方便,以后在windows上开发...然后去Microsoft Store搜索“在Windows上运行Linux”,...

    之前了解过一些适用于linux的Windows子系统,最近又听人提起,于是在自己的Windows 10专业版上安装了一个Ubuntu。运行起来还真方便,以后在windows上开发Linux程序就不需要安装桌面虚拟化应用了。下面讲下具体的步骤。

    首先需要在控制面板中启用“适用于Linux的Windows子系统”,

    然后去Microsoft Store搜索“在Windows上运行Linux”,

    当前可以免费下载的Linux系统包括 Ubuntu 、 openSUSE Leap 42 、SUSE Linux Enterprise Server 12

    下载安装ubuntu

    安装时会提示创建用户名和密码

    安装的过程非常快,几分钟就安装好了。安装后执行 sudo apt update & sudo apt upgrade

    用apt安装golang及godoc:sudo apt install golang-go  & sudo apt install golang-golang-x-tools

    查看安装及执行一些常用命令

    Linux之父Linus Torvalds加盟微软后,windows系统已经发生了比较大的改善;windows 10 做得不错,现在有了适用于Linux的Windows子系统,在Windows上

    进行跨平台开发太方便了,中遇可以摆脱不稳定的virtualbox虚拟机了。

    展开全文
  • 2、在Windows主机启动X服务器,并将Linux主机设为允许访问该Windows主机的X服务器。 #xhost +[IP of Linux host] 或 #xhost + //允许所有主机访问 3、在Windows主机用SecureCRT远程登录Linux主机 ...
  • andLinux是一个完整的Ubuntu Linux系统,它能够直接运行Windows 2000/XP/2003和Vista的32位版本,它由GP2X社区负责维护,而且是永久免费的.andLinux基于CoLinux开发的技术,它提供了一个让Windows连接Linux内核的...
  • Win10的wsl模式虽然解决了运行linux程序的痛点,然而所运行的程序依然受困于Terminal中。比如emacs:终端版本的emacs试图获得赏心悦目的视觉效果,比如优美的字体和图形,必须设法取得GUI。1.安装VcXsrv首先用 ...
  • 笔者曾经预言,Linux Bash是伟大的,我们很快就会看到“人们试图将包括桌面在内的所有Linux用户空间程序移植到Windows。” 在Windows Subsystem for Linux(WSL)发布的几天之后,黑客们就将L...
  • Windows10的wsl模式虽然解决了运行linux程序的痛点,然而所运行的程序依然受困于Terminal中。比如emacs:终端版本的emacs试图获得赏心悦目的视觉效果,比如优美的字体和图形,必须设法取得GUI。1.安装VcXsrv首先用 ...
  • Windows 上运行 Linux - 在 Windows 10 上运行 Ubuntu 16.04 LTS https://docs.microsoft.com/en-us/windows/wsl/about 1. 设置 2. Windows 设置 -> 更新和安全 3. 开发者选项 -> 开发人员模式 4. 此...
  • X windows,笼统的称为X,是一种位图显示的视窗系统,是建立图形用户界面的标准工具包和协议。X 是协议,不是具体的应用程序。X 为GUI环境提供了基本的框架:在屏幕绘图、移动视窗以及与鼠标键盘的互动。 现在...
  • windows上运行linux

    2018-10-19 16:08:00
    打开控制面板,单击“程序“,然后单击“打开Windows功能打开或关闭”在程序和功能。在这里启用“Windows子系统为Linux(测试版)”列表中的选项,并单击“确定”。 2.开发人员设置 打开设置应用程序和...
  • 而今天的这篇文章将会讲解如何自己实现一个简单的原生Linux程序运行器, 这个运行器在用户层实现, 原理和Bash On Windows不完全一样,比较接近Linux的Wine. 示例程序完整的代码在github, 地址是 ...
  • 作为一名开源软件爱好者;... 今天我们可以使用一种非常简单的方式来运行linux 软件在你的windows机子了-- 而你需要做的仅仅是下载并安装一个软件: AddLinux(点击下载)addLinux是一款完全免费的...
  • Linux操作系统上运行Windows应用程序
  • 当微软将把Ubuntu引入Windows 10的消息传出时,官方的理由是它只是针对将Bash移植到...笔者曾经预言,Linux Bash是伟大的,我们很快就会看到“人们试图将包括桌面在内的所有Linux用户空间程序移植到Windows
  • 之前了解过一些适用于linux的Windows子系统,最近又听人提起,于是在自己的Windows 10专业版上安装了一个Ubuntu。运行起来还真方便,以后在windows上...然后去Microsoft Store搜索“在Windows上运行Linux”, 当前可...
  • 本文同步Java知音社区,专注于Java作者:majianguohttp://cnblogs.com/majianguo/p/8047676.html...运行起来还真方便,以后在windows上开发Linux程序就不需要安装桌面虚拟化应用了。下面讲下具体的步骤。首先需要...
  • Wine 是一个令人神往而且目标远大的开放源代码项目,它尝试去解决在 Linux 上运行 Windows 可执行文件的复杂问题。尽管 Wine 不是一个新项目,但是,人们对 Linux 桌面的期望以及对 Linux 应用程序的需求日益增加,...
  • 安装和启动 旧版本的win10需要在“控制...启用或关闭Windows功能”勾选“适用于LinuxWindows子系统(Beta)” 由于现在这个功能已经不再是beta功能了,只要保证你的windows安装了最新的所有补丁与更新,这个...
  • 我对Python完全陌生,在...我的程序Windows上运行时运行得很好,所以我决定在Linux上测试它,因为最终我想在CRONTAB上运行它,作为一个从服务器获取信息并导出到XML的计划任务。这是我在Linux上编译相同代码时收到...
  • order=time&pos=&page=0 为什么同一个程序,在同一台计算机上,在Linux下可以运行,而在...反过来,Windows上程序Linux上也是一样不能执行的 1编译、链接和装载:拆解程序执行 一个程序执行的过程是什...
  • cygwin是一个在windows平台...它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,或者进行某些特殊的开发工作,尤其是使用gnu工具集在windows上进行嵌入式系统开发,非常有用。随着嵌入式系统开发在国

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,390
精华内容 2,556
关键字:

windows上运行linux程序

linux 订阅