如何实现在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 VABI 版本:                          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  000000000000000000000000  0000000000000000           0     0     0[ 1] .interp           PROGBITS         0000000000400238  00000238000000000000001c  0000000000000000   A       0     0     1[ 2] .note.ABI-tag     NOTE             0000000000400254  000002540000000000000020  0000000000000000   A       0     0     4[ 3] .note.gnu.build-i NOTE             0000000000400274  000002740000000000000024  0000000000000000   A       0     0     4[ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298000000000000001c  0000000000000000   A       5     0     8[ 5] .dynsym           DYNSYM           00000000004002b8  000002b80000000000000060  0000000000000018   A       6     1     8[ 6] .dynstr           STRTAB           0000000000400318  00000318000000000000003f  0000000000000000   A       0     0     1[ 7] .gnu.version      VERSYM           0000000000400358  000003580000000000000008  0000000000000002   A       5     0     2[ 8] .gnu.version_r    VERNEED          0000000000400360  000003600000000000000020  0000000000000000   A       6     1     8[ 9] .rela.dyn         RELA             0000000000400380  000003800000000000000018  0000000000000018   A       5     0     8[10] .rela.plt         RELA             0000000000400398  000003980000000000000030  0000000000000018  AI       5    24     8[11] .init             PROGBITS         00000000004003c8  000003c8000000000000001a  0000000000000000  AX       0     0     4[12] .plt              PROGBITS         00000000004003f0  000003f00000000000000030  0000000000000010  AX       0     0     16[13] .plt.got          PROGBITS         0000000000400420  000004200000000000000008  0000000000000000  AX       0     0     8[14] .text             PROGBITS         0000000000400430  0000043000000000000001f2  0000000000000000  AX       0     0     16[15] .fini             PROGBITS         0000000000400624  000006240000000000000009  0000000000000000  AX       0     0     4[16] .rodata           PROGBITS         0000000000400630  000006300000000000000050  0000000000000000   A       0     0     8[17] .eh_frame_hdr     PROGBITS         0000000000400680  00000680000000000000003c  0000000000000000   A       0     0     4[18] .eh_frame         PROGBITS         00000000004006c0  000006c00000000000000114  0000000000000000   A       0     0     8[19] .init_array       INIT_ARRAY       0000000000600e10  00000e100000000000000008  0000000000000000  WA       0     0     8[20] .fini_array       FINI_ARRAY       0000000000600e18  00000e180000000000000008  0000000000000000  WA       0     0     8[21] .jcr              PROGBITS         0000000000600e20  00000e200000000000000008  0000000000000000  WA       0     0     8[22] .dynamic          DYNAMIC          0000000000600e28  00000e2800000000000001d0  0000000000000010  WA       6     0     8[23] .got              PROGBITS         0000000000600ff8  00000ff80000000000000008  0000000000000008  WA       0     0     8[24] .got.plt          PROGBITS         0000000000601000  000010000000000000000028  0000000000000008  WA       0     0     8[25] .data             PROGBITS         0000000000601028  000010280000000000000010  0000000000000000  WA       0     0     8[26] .bss              NOBITS           0000000000601038  000010380000000000000008  0000000000000000  WA       0     0     1[27] .comment          PROGBITS         0000000000000000  000010380000000000000034  0000000000000001  MS       0     0     1[28] .shstrtab         STRTAB           0000000000000000  000018ea000000000000010c  0000000000000000           0     0     1[29] .symtab           SYMTAB           0000000000000000  000010700000000000000660  0000000000000018          30    47     8[30] .strtab           STRTAB           0000000000000000  000016d0000000000000021a  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           PhysAddrFileSiz            MemSiz              Flags  AlignPHDR           0x0000000000000040 0x0000000000400040 0x00000000004000400x00000000000001f8 0x00000000000001f8  R E    8INTERP         0x0000000000000238 0x0000000000400238 0x00000000004002380x000000000000001c 0x000000000000001c  R      1[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]LOAD           0x0000000000000000 0x0000000000400000 0x00000000004000000x00000000000007d4 0x00000000000007d4  R E    200000LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e100x0000000000000228 0x0000000000000230  RW     200000DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e280x00000000000001d0 0x00000000000001d0  RW     8NOTE           0x0000000000000254 0x0000000000400254 0x00000000004002540x0000000000000044 0x0000000000000044  R      4GNU_EH_FRAME   0x0000000000000680 0x0000000000400680 0x00000000004006800x000000000000003c 0x000000000000003c  R      4GNU_STACK      0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000  RW     10GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e100x00000000000001f0 0x00000000000001f0  R      1Section 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)               0x4003c80x000000000000000d (FINI)               0x4006240x0000000000000019 (INIT_ARRAY)         0x600e100x000000000000001b (INIT_ARRAYSZ)       8 (bytes)0x000000000000001a (FINI_ARRAY)         0x600e180x000000000000001c (FINI_ARRAYSZ)       8 (bytes)0x000000006ffffef5 (GNU_HASH)           0x4002980x0000000000000005 (STRTAB)             0x4003180x0000000000000006 (SYMTAB)             0x4002b80x000000000000000a (STRSZ)              63 (bytes)0x000000000000000b (SYMENT)             24 (bytes)0x0000000000000015 (DEBUG)              0x00x0000000000000003 (PLTGOT)             0x6010000x0000000000000002 (PLTRELSZ)           48 (bytes)0x0000000000000014 (PLTREL)             RELA0x0000000000000017 (JMPREL)             0x4003980x0000000000000007 (RELA)               0x4003800x0000000000000008 (RELASZ)             24 (bytes)0x0000000000000009 (RELAENT)            24 (bytes)0x000000006ffffffe (VERNEED)            0x4003600x000000006fffffff (VERNEEDNUM)         10x000000006ffffff0 (VERSYM)             0x4003580x0000000000000000 (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 + 0The 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 Name0: 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 Name0: 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.c29: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   21 __JCR_LIST__30: 0000000000400460     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones31: 00000000004004a0     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones32: 00000000004004e0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux33: 0000000000601038     1 OBJECT  LOCAL  DEFAULT   26 completed.758534: 0000000000600e18     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtors_aux_fin35: 0000000000400500     0 FUNC    LOCAL  DEFAULT   14 frame_dummy36: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_init_array_37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c38: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c39: 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_end43: 0000000000600e28     0 OBJECT  LOCAL  DEFAULT   22 _DYNAMIC44: 0000000000600e10     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start45: 0000000000400680     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR46: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_47: 0000000000400620     2 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini48: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab49: 0000000000601028     0 NOTYPE  WEAK   DEFAULT   25 data_start50: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 _edata51: 0000000000400624     0 FUNC    GLOBAL DEFAULT   15 _fini52: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.553: 0000000000400526    22 FUNC    GLOBAL DEFAULT   14 max54: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_55: 0000000000601028     0 NOTYPE  GLOBAL DEFAULT   25 __data_start56: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__57: 0000000000601030     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle58: 0000000000400630     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used59: 00000000004005b0   101 FUNC    GLOBAL DEFAULT   14 __libc_csu_init60: 0000000000601040     0 NOTYPE  GLOBAL DEFAULT   26 _end61: 0000000000400430    42 FUNC    GLOBAL DEFAULT   14 _start62: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start63: 000000000040053c   109 FUNC    GLOBAL DEFAULT   14 main64: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses65: 0000000000601038     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__66: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable67: 00000000004003c8     0 FUNC    GLOBAL DEFAULT   11 _initVersion 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  计数:10x0010:名称:GLIBC_2.2.5  标志:无  版本:2Displaying notes found at file offset 0x00000254 with length 0x00000020:Owner                 Data size   DescriptionGNU                  0x00000010   NT_GNU_ABI_TAG (ABI version tag)OS: Linux, ABI: 2.6.32Displaying notes found at file offset 0x00000274 with length 0x00000024:Owner                 Data size   DescriptionGNU                  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 oncenamespace 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]; 

转载于:https://www.cnblogs.com/zhehan54/p/6898084.html

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

  1. linux 正在运行的程序不能拷贝_如何实现在Windows上运行Linux程序,附示例代码

    初步了解ELF格式 首先让我们先了解什么是原生Linux程序, 以下说明摘自维基百科 In computing, the Executable and Linkable Format (ELF, fo ...

  2. 双用户windows linux系统,Windows与Linux合二为一?终于能在windows上运行Linux了!

    原标题:Windows与Linux合二为一?终于能在windows上运行Linux了! 目前在PC端操作系统市场份额中,微软旗下的windows系统占据超过50%的比例. 作为微软旗下发布的产品之一, ...

  3. 运行linux中degui_Windows与Linux合二为一?终于能在windows上运行Linux了!

    目前在PC端操作系统市场份额中,微软旗下的windows系统占据超过50%的比例. 作为微软旗下发布的产品之一,windows系统深受用户喜爱.从经典的XP和win7,因其操作简单,运行流畅吸粉无数, ...

  4. linux运行容器,容器与云|如何在 Windows 上运行 Linux 容器

    1.概述 现在能够在 Windows 10 和 Windows 服务器上运行 Docker 容器了,它是以 Ubuntu 作为宿主基础的. 想象一下,使用你喜欢的 Linux 发行版--比如 Ubun ...

  5. 单片机上运行linux程序代码,在Linux下烧录51单片机

    原标题:在Linux下烧录51单片机 *本文作者:LEdge1,本文属 FreeBuf原创奖励计划,未经许可禁止转载. 背景 我一直在学习Linux 系统,但是最近还要学习51单片机,所以在Linux ...

  6. win10上运行linux程序吗,Win10可以运行 Linux 的图形界面程序了

    Win10可以运行 Linux 的图形界面程序了 2016年04月13日 16:39作者:cnBeta编辑:李佳辉 分享 正如大家所知道的,大多数 Linux 上的命令行二进制程序现在可以原生地运行在 ...

  7. wsl(windows上运行linux)安装到非C盘解决方案

    前言 最近有小伙伴在问wsl默认安装在C盘的问题,觉得安装在C盘太占内存,毕竟一般新买的电脑默认C盘也就分了100多G,时间久了确实不够用.以前我还真没关注过这个问题,但是最近我发现我的C盘也越来越小 ...

  8. linux容器怎么运行到windows,如何在 Windows 上运行 Linux 容器?

    首先,我们来做一下准备工作,计算机的大概配置内存8GB和64 位的计算机,可以运行 Windows 10 或 Windows Server.已经加入了 Windows 预览体验计划(Insider), ...

  9. 在windows上开发linux程序

    1. 概述 由于工作需要,希望能把现有代码移植到linux.基于此目的,最近做了些调研和实验. 由于自己并没有太多的linux下的工作经验,所以不考虑直接在linux平台下工作,开发. 好在现在VSC ...

最新文章

  1. 【OpenCV 】直方图均衡化,直方图计算,直方图对比
  2. 985高校博士情侣致谢:我俩每月补贴600元,在一线城市生活5年
  3. Django框架视图类
  4. gson生成jsonobject_使用GSON将字符串解析为JsonObject会产生IllegalStateException:这不是JSON对象...
  5. compose应用_带有PostgreSQLDocker Compose for Spring Boot应用程序
  6. 被吹得天花乱坠的无服务器架构,究竟是什么?
  7. LeetCode题解-23 合并K个排序链表 Hard
  8. 华为云GaussDB(for MySQL)2.0全新升级,三大技术大揭秘
  9. 11dayC语言指针-指针变量
  10. LTI系统对WSS Processes的作用
  11. 深入浅出SpringSecurity
  12. GIS应用实例--模型预测、多元回归、空间自相关分析
  13. 计算机控制技术电子课件,电子科技大学计算机控制技术课件04.ppt
  14. ios android 逆向 对比,iOS逆向开发--APP重签名
  15. 计算机课程总结800字,计算机课程心得体会范文800字(通用5篇)
  16. 使用vue-router却导致页面空白无法呈现-报错?
  17. 机考[51 - 60]
  18. 使用NoteExpress引入参考文献
  19. React Native开发之——Webstorm开发RN配置
  20. java cda安装_JAVA如何与R完美结合起来

热门文章

  1. Java操作某方法时报错:java.lang.NoSuchMethodError
  2. Centos7开放及查看端口
  3. Android开发笔记(九十八)往图片添加部件
  4. 随机生成指定个数学生的语文数学外语成绩并求平均值
  5. VS2017专业版使用最新版Qt5.9.2教程(转载)
  6. virtualbox+vagrant学习-2(command cli)-7-vagrant login命令
  7. Ionic如何实现单选二级菜单切换
  8. Linux系统、版本、CPU、内存查看、硬盘空间
  9. C语言 · 输出日历
  10. java synchronized讨论