Android so库文件的区节section修复代码分析
阅读原文时间:2021年09月06日阅读:1

本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78818917

一、Android so库文件的节表secion修复方案整理

1.简单粗暴的so加解密实现

https://bbs.pediy.com/thread-191649.htm

            2. ELF section修复的一些思考

https://bbs.pediy.com/thread-192874.htm

            3. 从零打造简单的SODUMP工具

https://bbs.pediy.com/thread-194053.htm

            4. 基于init_array加密的SO的脱壳

http://ele7enxxh.com/Unpack-Android-Shared-Library-Based-On-Init_Array-Encryption.html

            5. ELF文件格式学习,section修复

http://blog.csdn.net/yi_nuo_wang/article/details/72626846

            6. Android逆向中So模块自动化修复工具+实战一发

https://bbs.pediy.com/thread-221741.htm

            7. Android加固中So文件自动化修复工具GUI

https://bbs.pediy.com/thread-221878.htm

            8. SoFixer

https://github.com/F8LEFT/SoFixer

二、Android so库文件的节表secion修复的方案讨论

Android so库文件的节表secion修复的方法,最早是由 ThomasKing 在《ELF section修复的一些思考》一文中提到的,尽管方法还不是很完美但是使用 IDA  Pro 对修复后Android so库文件进行静态逆向分析,效果还是不错的。需要提到的是:Android系统 7.0 以后,Android系统在进行Android
so库文件的加载时,会对加载的Android so库文件 ELF 格式的seciton节表进行检查和判断,因此以后为了兼顾Android 7.0的系统,Android加固会保留被保护Android so库文件的section节表,但是并不代表Android加固会减弱对Android so库文件的保护。

被Android 加固保护的Android so库文件尽管已经失去了 ELF 文件格式的section节表头段信息,但是通过 ThomasKing 提到的ELF section修复的方法,还是可以修复绝大部分的对静态逆向分析有用的seciton节表头段。ELF 文件格式有两种视图:链接视图和执行视图,ELF文件在编译链接的时候需要链接格式的视图,在ELF文件执行的时候需要执行视图不需要链接视图。

Android so库文件加载到内存并解析链接主要依赖于ELF文件格式的可执行视图,在ELF文件可执行视图的情况下,有一个重要结构的 程序段描述头  .dynamic段,.dynamic段里保存了动态连接器所需要的基本信息如下图所示:

很显然,根据ELF文件可执行视图时的.dynamic段描述的一些信息,能够获取到ELF文件链接视图时的一些重要区节表头的偏移和大小信息,可以完成对这些section区节的重建,.dynamic段 在Android so库文件的动态链接时的实现代码如下所示(以Android 4.4.4 r1的源码为例):

static bool soinfo_link_image(soinfo* si) {
    /* "base" might wrap around UINT32_MAX. */
    Elf32_Addr base = si->load_bias;
    const Elf32_Phdr *phdr = si->phdr;
    int phnum = si->phnum;
    bool relocating_linker = (si->flags & FLAG_LINKER) != 0;

    /* We can't debug anything until the linker is relocated */
    if (!relocating_linker) {
        INFO("[ linking %s ]", si->name);
        DEBUG("si->base = 0x%08x si->flags = 0x%08x", si->base, si->flags);
    }

    /* Extract dynamic section */
    size_t dynamic_count;
    Elf32_Word dynamic_flags;
    phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,
                                   &dynamic_count, &dynamic_flags);
    if (si->dynamic == NULL) {
        if (!relocating_linker) {
            DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name);
        }
        return false;
    } else {
        if (!relocating_linker) {
            DEBUG("dynamic = %p", si->dynamic);
        }
    }

#ifdef ANDROID_ARM_LINKER
    (void) phdr_table_get_arm_exidx(phdr, phnum, base,
                                    &si->ARM_exidx, &si->ARM_exidx_count);
#endif

    // Extract useful information from dynamic section.
    // 从动态连接段.dynamic段获取重要信息
    uint32_t needed_count = 0;
    for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x", d, d->d_tag, d->d_un.d_val);
        switch(d->d_tag){
        case DT_HASH:
            si->nbucket = ((unsigned *) (base + d->d_un.d_ptr))[0];
            si->nchain = ((unsigned *) (base + d->d_un.d_ptr))[1];
            si->bucket = (unsigned *) (base + d->d_un.d_ptr + 8);
            si->chain = (unsigned *) (base + d->d_un.d_ptr + 8 + si->nbucket * 4);
            break;
        case DT_STRTAB:
            si->strtab = (const char *) (base + d->d_un.d_ptr);
            break;
        case DT_SYMTAB:
            si->symtab = (Elf32_Sym *) (base + d->d_un.d_ptr);
            break;
        case DT_PLTREL:
            if (d->d_un.d_val != DT_REL) {
                DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
                return false;
            }
            break;
        case DT_JMPREL:
            si->plt_rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
            break;
        case DT_PLTRELSZ:
            si->plt_rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
            break;
        case DT_REL:
            si->rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
            break;
        case DT_RELSZ:
            si->rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
            break;
        case DT_PLTGOT:
            /* Save this in case we decide to do lazy binding. We don't yet. */
            si->plt_got = (unsigned *)(base + d->d_un.d_ptr);
            break;
        case DT_DEBUG:
            // Set the DT_DEBUG entry to the address of _r_debug for GDB
            // if the dynamic table is writable
            if ((dynamic_flags & PF_W) != 0) {
                d->d_un.d_val = (int) &_r_debug;
            }
            break;
         case DT_RELA:
            DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
            return false;
        case DT_INIT:
            si->init_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
            DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func);
            break;
        case DT_FINI:
            si->fini_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
            DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func);
            break;
        case DT_INIT_ARRAY:
            si->init_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
            DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
            break;
        case DT_INIT_ARRAYSZ:
            si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
            break;
        case DT_FINI_ARRAY:
            si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
            DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
            break;
        case DT_FINI_ARRAYSZ:
            si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
            break;
        case DT_PREINIT_ARRAY:
            si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
            DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
            break;
        case DT_PREINIT_ARRAYSZ:
            si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
            break;
        case DT_TEXTREL:
            si->has_text_relocations = true;
            break;
        case DT_SYMBOLIC:
            si->has_DT_SYMBOLIC = true;
            break;
        case DT_NEEDED:
            ++needed_count;
            break;
#if defined DT_FLAGS
        // TODO: why is DT_FLAGS not defined?
        case DT_FLAGS:
            if (d->d_un.d_val & DF_TEXTREL) {
                si->has_text_relocations = true;
            }
            if (d->d_un.d_val & DF_SYMBOLIC) {
                si->has_DT_SYMBOLIC = true;
            }
            break;
#endif
#if defined(ANDROID_MIPS_LINKER)
        case DT_STRSZ:
        case DT_SYMENT:
        case DT_RELENT:
             break;
        case DT_MIPS_RLD_MAP:
            // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
            {
              r_debug** dp = (r_debug**) d->d_un.d_ptr;
              *dp = &_r_debug;
            }
            break;
        case DT_MIPS_RLD_VERSION:
        case DT_MIPS_FLAGS:
        case DT_MIPS_BASE_ADDRESS:
        case DT_MIPS_UNREFEXTNO:
            break;

        case DT_MIPS_SYMTABNO:
            si->mips_symtabno = d->d_un.d_val;
            break;

        case DT_MIPS_LOCAL_GOTNO:
            si->mips_local_gotno = d->d_un.d_val;
            break;

        case DT_MIPS_GOTSYM:
            si->mips_gotsym = d->d_un.d_val;
            break;

        default:
            DEBUG("Unused DT entry: type 0x%08x arg 0x%08x", d->d_tag, d->d_un.d_val);
            break;
#endif
        }
    }

    DEBUG("si->base = 0x%08x, si->strtab = %p, si->symtab = %p",
          si->base, si->strtab, si->symtab);

    // Sanity checks.
    if (relocating_linker && needed_count != 0) {
        DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
        return false;
    }
    if (si->nbucket == 0) {
        DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name);
        return false;
    }
    if (si->strtab == 0) {
        DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name);
        return false;
    }
    if (si->symtab == 0) {
        DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name);
        return false;
    }

    // If this is the main executable, then load all of the libraries from LD_PRELOAD now.
    if (si->flags & FLAG_EXE) {
        memset(gLdPreloads, 0, sizeof(gLdPreloads));
        size_t preload_count = 0;
        for (size_t i = 0; gLdPreloadNames[i] != NULL; i++) {
            soinfo* lsi = find_library(gLdPreloadNames[i]);
            if (lsi != NULL) {
                gLdPreloads[preload_count++] = lsi;
            } else {
                // As with glibc, failure to load an LD_PRELOAD library is just a warning.
                DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s",
                        gLdPreloadNames[i], si->name, linker_get_error_buffer());
            }
        }
    }

    soinfo** needed = (soinfo**) alloca((1 + needed_count) * sizeof(soinfo*));
    soinfo** pneeded = needed;

    for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        if (d->d_tag == DT_NEEDED) {
            const char* library_name = si->strtab + d->d_un.d_val;
            DEBUG("%s needs %s", si->name, library_name);
            soinfo* lsi = find_library(library_name);
            if (lsi == NULL) {
                strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
                       library_name, si->name, tmp_err_buf);
                return false;
            }
            *pneeded++ = lsi;
        }
    }
    *pneeded = NULL;

    if (si->has_text_relocations) {
        /* Unprotect the segments, i.e. make them writable, to allow
         * text relocations to work properly. We will later call
         * phdr_table_protect_segments() after all of them are applied
         * and all constructors are run.
         */
        DL_WARN("%s has text relocations. This is wasting memory and is "
                "a security risk. Please fix.", si->name);
        if (phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
            DL_ERR("can't unprotect loadable segments for \"%s\": %s",
                   si->name, strerror(errno));
            return false;
        }
    }

    if (si->plt_rel != NULL) {
        DEBUG("[ relocating %s plt ]", si->name );
        if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) {
            return false;
        }
    }
    if (si->rel != NULL) {
        DEBUG("[ relocating %s ]", si->name );
        if (soinfo_relocate(si, si->rel, si->rel_count, needed)) {
            return false;
        }
    }

#ifdef ANDROID_MIPS_LINKER
    if (!mips_relocate_got(si, needed)) {
        return false;
    }
#endif

    si->flags |= FLAG_LINKED;
    DEBUG("[ finished linking %s ]", si->name);

    if (si->has_text_relocations) {
        /* All relocations are done, we can protect our segments back to
         * read-only. */
        if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
            DL_ERR("can't protect segments for \"%s\": %s",
                   si->name, strerror(errno));
            return false;
        }
    }

    /* We can also turn on GNU RELRO protection */
    if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) {
        DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
               si->name, strerror(errno));
        return false;
    }

    notify_gdb_of_load(si);
    return true;
}

通过Android NDK提供的工具 readelf程序 可以查看ELF文件格式相关的信息,执行 **readelf -l  xxx.so
**命令可以查看ELF文件的链接视图 区节section 和 可执行视图的 段 segment
的映射对应关系如下所示,再结合可执行视图时 .dynamic段 解析所能获取到的一些重要的区节表头的内存相对虚拟地址(VA)和大小(size)信息,可以实现ELF文件的链接视图重要区节section的重建,这也是 ThomasKing 提供的ELF文件节表section修复的思路。现在有些Android加固为了防止Android so库文件的节表section被修复,在外壳Android so库文件的构造函数调用时完成了JNI_Onload函数的代码解密之后,会将外壳Android
so库文件的ELF文件头和程序段segment表的信息在内存抹掉,防止外壳Android so库文件的内存dump和dump之后的节表section被修复。

在文章《ELF section修复的一些思考》中,ThomasKing 提供的Android so库文件的节表section修复的思路整理如下:

从segment信息可以看出, 对.dynamic和.arm_exidx的section重建很简单,即读取即可。

 通过.dynamic段,可以对大部分section进行重建,具体如下:

1. 通过DT_SYMTAB,DT_STRTAB,DT_STRSZ,DT_REL,DT_RELSZ,DT_JMPREL, DT_PLTRELSZ,DT_INIT_ARRAY,DT_INIT_ARRAYSZ,DT_FINI_ARRAY,DT_FINI_ARRAYSZ 得到.dynsym,.dynstr,  rel.dyn,  rel.plt,  init_array,  fini_array
相应的section vaddr 和 size信息,完成对上述section的重建。这里需要注意,处于load2中的section,offset = vaddr – 0x1000。

2. 通过DT_HASH得到hash section的vaddr,然后读入前两项得到nbucket和nchain的值,得到hashsz = (nbucket + nchain + 2) * sizeof(int), 完成对hash表重建。

3. Plt的起始位置即为rel.plt的末尾,通过1中的对rel.plt的处理,即可得到plt的offset和vaddr信息。通过plt的结构知道,plt由固定16字节 + 4字节的__global__offset_table变量和n个需要重定位的函数地址构成,函数地址又与rel.plt中的结构一一对应。故size = (20 + 12 * (rel.plt.size) / sizeof(Elf32_Rel)。

4.  从DT_PLTGOT可以得到__global_offset_table的偏移位置。由got表的结构知道,__global_offset_table前是rel.dyn重定位结构,之后为rel.plt重定位结构,都与rel一一对应。则got表的重建具体为:通过已重建的.dynamic得到got起始位置,通过__global_offset_table 偏移 + 4 * (rel.plt.size)
/ sizeof(Elf32_Rel)(这里还需要添加2个int的填充位置)得到got的末尾,通过首尾位置得到got的size,完成重建。

5. 通过got的末尾,得到data的起始位置,再通过load2_vaddr + load2_filesz得到load2的末尾(load2即第二个LOAD),即data的末尾位置,计算长度,完成修正。可能读者会问,bss才是load2的最后一个section。的确,但bss为NOBITS,即可把data看作load2最后一个section。

6. 对bss的修正就很简单,offset和vaddr即为load2末尾。由于未NOBITS类型,长度信息无关紧要。

7. 到这里,读者可能已经发现,还没对text和ARM.extab修正。限于本人水平,还没能找到方法区分开这两个section。现处理是将之合并,作为text & ARM.extab节。具体修正:offset和vaddr通过plt末尾得到,长度通过ARM.exidx的起始位置和plt末尾位置计算得到。

8.  至此,绝大部分section信息已经重建完成。最后,在将shstrtab添加,并修正Elf32_Ehdr,完成section重建。虽然未100%重建,但已经能够帮助分析了。重建后的如图所示,图中红色部分即是未分离的test & ARM.extab section。

文章《ELF文件格式学习,section修复》就是根据ThomasKing 提供的Android so库文件的节表section修复的思路实现的代码,但是该作者提供的代码还是有一些小问题,比如说,关于ELF文件的节表section修复时候,申请存放section头表内存的大小(应该使用elf文件加载到内存后的文件大小,因为Android
so加固会修改ELF文件头中关于section区节的描述变量如偏移、大小等信息)以及构造的seciton区节名称字符串表的存放文件偏移有点小问题(第2个P_LOAD段结束的位置偏移),不应该按照这个思路去处理,并且作者给出的代码只能适用于从内存中dump出的Android so库文件的修复,考虑的还不是很周到。本来打算将作者的代码优化和修改一下的,但是没那么多精力,就不献丑了,还是要感谢原作者王一诺和ThomasKing。

文章《ELF文件格式学习,section修复》的作者在进行seciton重建的时候,对区节section段的描述结构体
Elf32_Shdr  中,除sh_addr、sh_offset、sh_size、sh_name之外的其他成员变量的信息没有修正,其实修正也很简单,直接按照下图中 Android so库文件 链接视图中区节section信息 进行对应区节section头表段成员变量属性值的修正。通过Android NDK 提供的工具readelf,执行
readelf –S 命令,即可得到Android so库文件的链接视图时的各区节section段的描述结构体Elf32_Shdr的其他成员变量的属性值,对照着对应的段进行Elf32_Shdr结构体其他成员变量的属性值的修正。

typedef struct elf32_shdr {
  Elf32_Word    sh_name;
  Elf32_Word    sh_type;
  Elf32_Word    sh_flags;
  Elf32_Addr    sh_addr;
  Elf32_Off    sh_offset;
  Elf32_Word    sh_size;
  Elf32_Word    sh_link;
  Elf32_Word    sh_info;
  Elf32_Word    sh_addralign;
  Elf32_Word    sh_entsize;
} Elf32_Shdr;

typedef struct elf64_shdr {
  Elf64_Word sh_name;    /* Section name, index in string tbl */
  Elf64_Word sh_type;    /* Type of section */
  Elf64_Xword sh_flags;    /* Miscellaneous section attributes */
  Elf64_Addr sh_addr;    /* Section virtual addr at execution */
  Elf64_Off sh_offset;    /* Section file offset */
  Elf64_Xword sh_size;    /* Size of section in bytes */
  Elf64_Word sh_link;    /* Index of another section */
  Elf64_Word sh_info;    /* Additional section information */
  Elf64_Xword sh_addralign;    /* Section alignment */
  Elf64_Xword sh_entsize;    /* Entry size if section holds table */
} Elf64_Shdr;

文章《ELF文件格式学习,section修复》的作者对 ThomasKing 提出的ELF文件的区节表section修复方案的思考和疑问。

三、对文章《ELF文件格式学习,section修复》中的代码进行分析。

对文章《ELF文件格式学习,section修复》中 提到的代码进行了注释分析,工程主要有3个源码文件 elf.hfix.h、**fix.c
**组成,Android so库文件区节section修复主要操作的源码文件 fix.c 的代码注释如下:

#define _CRT_SECURE_NO_WARNINGS
#include "fix.h"

#ifndef SHT_ARM_EXIDX
#define SHT_ARM_EXIDX (SHT_LOPROC + 1)
#endif

#define SHT_INIT_ARRAY      14
#define SHT_FINI_ARRAY      15

#define SHF_LINK_ORDER         (1 << 7)   /* Preserve order after combining */

char* str = "..dynsym..dynstr..hash..rel.dyn..rel.plt..text..ARM.extab..ARM.exidx..fini_array..init_array..dynamic..got..data..bass..shstrtab\0";
char* str1 = "..dynsym\0.dynstr\0.hash\0.rel.dyn\0.rel.plt\0.text\0.ARM.extab\0.ARM.exidx\0.fini_array\0.init_array\0.dynamic\0.got\0.data\0.bass\0.shstrtab\0";
Elf32_Shdr shdr[SHDRS] = { 0 };

// 读取ELF文件的Elf32_Ehdr信息
void get_elf_header(char* buffer, Elf32_Ehdr** pehdr)
{
    int header_len = sizeof(Elf32_Ehdr);
    memset(*pehdr, 0, header_len);
    memcpy(*pehdr, (void*)buffer, header_len);
}

// 读取ELF文件的程序头表的信息
void get_program_table(Elf32_Ehdr ehdr, char* buffer, Elf32_Phdr** pphdr)
{
    int ph_size = ehdr.e_phentsize;
    int ph_num = ehdr.e_phnum;
    memset(*pphdr, 0, ph_size * ph_num);
    memcpy(*pphdr, buffer + ehdr.e_phoff,ph_size * ph_num);
}

// 获取需要修复的Android so文件的大小
long get_file_len(FILE* p)
{
    fseek (p, 0, SEEK_END);

    // 获取到整个文件的大小
    long fsize = ftell (p);

    // 重新设置文件指针到开头
    rewind (p);
    return fsize;
}

// 进行需要修复的ELF文件的区节头表的重建
void get_Info(Elf32_Phdr* phdr, Elf32_Ehdr *pehdr, char* buffer,
    char** sh_buffer, int sh_len)
{
    Elf32_Dyn* dyn = NULL;
    Elf32_Dyn* d = NULL;
    Elf32_Phdr load = { 0 };

    int ph_num = pehdr->e_phnum;
    int dyn_size = 0, dyn_off = 0;
    int nbucket = 0, nchain = 0;
    int flag = 0, i = 0;

    // 用于存放ELF文件的区节头表信息
    memset(*sh_buffer, 0, sh_len);

    i = 0;
    for(;i < ph_num;i++) {

        if (phdr[i].p_type == PT_LOAD) {

            if (phdr[i].p_vaddr > 0x0) {

                load = phdr[i];

                // 进行 .bss 区节头的重建
                shdr[BSS].sh_name = strstr(str,".bss") - str;
                shdr[BSS].sh_type = SHT_NOBITS;
                shdr[BSS].sh_flags = SHF_WRITE | SHF_ALLOC;
                shdr[BSS].sh_addr =  phdr[i].p_vaddr + phdr[i].p_filesz;
                shdr[BSS].sh_offset = shdr[BSS].sh_addr - 0x1000;
                shdr[BSS].sh_size = 0;
                shdr[BSS].sh_link = 0;
                shdr[BSS].sh_info = 0;
                shdr[BSS].sh_entsize = 0
                shdr[BSS].sh_addralign = 1;

                continue;
            }
        }

        if(phdr[i].p_type == PT_DYNAMIC) {

            // 进行 .dynamic 区节头的重建
            // 设置".dynamic"区节头名称在.shstr.tab中的偏移值
            shdr[DYNAMIC].sh_name = strstr(str, ".dynamic") - str;
            shdr[DYNAMIC].sh_type = SHT_DYNAMIC;
            shdr[DYNAMIC].sh_flags = SHF_WRITE | SHF_ALLOC;
            shdr[DYNAMIC].sh_addr = phdr[i].p_vaddr;
            shdr[DYNAMIC].sh_offset = phdr[i].p_offset;
            shdr[DYNAMIC].sh_size = phdr[i].p_filesz;
            shdr[DYNAMIC].sh_link = 2;
            shdr[DYNAMIC].sh_info = 0;
            shdr[DYNAMIC].sh_addralign = 4;
            shdr[DYNAMIC].sh_entsize = 8;

            // 得到.dynamic区节段的数据
            dyn_off = phdr[i].p_offset;
            dyn_size = phdr[i].p_filesz;
            continue;
        }

        // ThomasKing修复时使用的是PT_LOPROC + 1
        if(phdr[i].p_type == PT_LOPROC || phdr[i].p_type == PT_LOPROC + 1) {

            // 进行".ARM.exidx" 区节头的重建
            shdr[ARMEXIDX].sh_name = strstr(str, ".ARM.exidx") - str;
            shdr[ARMEXIDX].sh_type = SHT_ARM_EXIDX;
            shdr[ARMEXIDX].sh_flags = SHF_ALLOC + SHF_LINK_ORDER;
            shdr[ARMEXIDX].sh_addr = phdr[i].p_vaddr;
            shdr[ARMEXIDX].sh_offset = phdr[i].p_offset;
            shdr[ARMEXIDX].sh_size = phdr[i].p_filesz;
            shdr[ARMEXIDX].sh_link = 7;
            shdr[ARMEXIDX].sh_info = 0;
            shdr[ARMEXIDX].sh_addralign = 4;
            shdr[ARMEXIDX].sh_entsize = 8;
            continue;
        }
    }

    // 申请内存空间
    dyn = (Elf32_Dyn*)malloc(dyn_size);
    // 获取整个".dynamic"区节的数据(Elf32_Dyn[]数组)
    memcpy(dyn, buffer+dyn_off, dyn_size);

    i = 0;
    // 对".dynamic"区节的数据进行解析处理
    for (; i < dyn_size / sizeof(Elf32_Dyn); i++) {

        switch (dyn[i].d_tag) {

            case DT_SYMTAB:
                // 对动态符号表 .dynsym 区节头进行重建
                shdr[DYNSYM].sh_name = strstr(str, ".dynsym") - str;
                shdr[DYNSYM].sh_type = SHT_DYNSYM;
                shdr[DYNSYM].sh_flags = SHF_ALLOC;
                shdr[DYNSYM].sh_addr = dyn[i].d_un.d_ptr;
                shdr[DYNSYM].sh_offset = dyn[i].d_un.d_ptr;
                shdr[DYNSYM].sh_link = 2;
                shdr[DYNSYM].sh_info = 1;
                shdr[DYNSYM].sh_addralign = 4;
                shdr[DYNSYM].sh_entsize = 16;
                // shdr[DYNSYM].sh_size还需要修复
                break;

            case DT_STRTAB:
                // 对动态符号表 .dynstr 区节头进行重建
                shdr[DYNSTR].sh_name = strstr(str, ".dynstr") - str;
                shdr[DYNSTR].sh_type = SHT_STRTAB;
                shdr[DYNSTR].sh_flags = SHF_ALLOC;
                shdr[DYNSTR].sh_offset = dyn[i].d_un.d_ptr;
                shdr[DYNSTR].sh_addr = dyn[i].d_un.d_ptr;
                // 添加的
                shdr[DYNSYM].sh_link = 0;
                shdr[DYNSYM].sh_info = 0;
                //
                shdr[DYNSTR].sh_addralign = 1;
                shdr[DYNSTR].sh_entsize = 0;
                break;

            case DT_HASH:
                // 对符号哈希表 .hash 的区节头进行重建
                shdr[HASH].sh_name = strstr(str, ".hash") - str;
                shdr[HASH].sh_type = SHT_HASH;
                shdr[HASH].sh_flags = SHF_ALLOC;
                shdr[HASH].sh_addr = dyn[i].d_un.d_ptr;
                shdr[HASH].sh_offset = dyn[i].d_un.d_ptr;
                memcpy(&nbucket, buffer + shdr[HASH].sh_offset, 4);
                memcpy(&nchain, buffer + shdr[HASH].sh_offset + 4, 4);
                // 和.hash区节的数据结构有关
                shdr[HASH].sh_size = (nbucket + nchain + 2) * sizeof(int);
                shdr[HASH].sh_link = 1;
                shdr[HASH].sh_info = 0;
                shdr[HASH].sh_addralign = 4;
                shdr[HASH].sh_entsize = 4;
                break;

            case DT_REL:
                // 对 .rel.dyn 的区节头进行重建
                shdr[RELDYN].sh_name = strstr(str, ".rel.dyn") - str;
                shdr[RELDYN].sh_type = SHT_REL;
                shdr[RELDYN].sh_flags = SHF_ALLOC;
                shdr[RELDYN].sh_addr = dyn[i].d_un.d_ptr;
                shdr[RELDYN].sh_offset = dyn[i].d_un.d_ptr;
                shdr[RELDYN].sh_link = 1;
                shdr[RELDYN].sh_info = 0;
                shdr[RELDYN].sh_addralign = 4;
                shdr[RELDYN].sh_entsize = 8;
                break;

            case DT_JMPREL:
                // 对 .rel.plt 的区节头进行重建
                shdr[RELPLT].sh_name = strstr(str, ".rel.plt") - str;
                shdr[RELPLT].sh_type = SHT_REL;
                shdr[RELPLT].sh_flags = SHF_ALLOC;
                shdr[RELPLT].sh_addr = dyn[i].d_un.d_ptr;
                shdr[RELPLT].sh_offset = dyn[i].d_un.d_ptr;
                shdr[RELPLT].sh_link = 1;
                shdr[RELPLT].sh_info = 6;
                shdr[RELPLT].sh_addralign = 4;
                shdr[RELPLT].sh_entsize = 8;
                break;

            case DT_PLTRELSZ:
                shdr[RELPLT].sh_size = dyn[i].d_un.d_val;
                break;

            case DT_FINI:
                // 对.fini_array 的区节头进行重建
                shdr[FINIARRAY].sh_name = strstr(str, ".fini_array") - str;
                shdr[FINIARRAY].sh_type = SHT_FINI_ARRAY;
                shdr[FINIARRAY].sh_flags = SHF_WRITE | SHF_ALLOC;
                shdr[FINIARRAY].sh_offset = dyn[i].d_un.d_ptr - 0x1000;
                shdr[FINIARRAY].sh_addr = dyn[i].d_un.d_ptr;
                shdr[FINIARRAY].sh_link = 0
                shdr[FINIARRAY].sh_info = 0
                shdr[FINIARRAY].sh_addralign = 4;
                shdr[FINIARRAY].sh_entsize = 0;
                break;

            case DT_INIT:
                // 对.init_array 的区节头进行重建
                shdr[INITARRAY].sh_name = strstr(str, ".init_array") - str;
                shdr[INITARRAY].sh_type = SHT_INIT_ARRAY;
                shdr[INITARRAY].sh_flags = SHF_WRITE | SHF_ALLOC;
                shdr[INITARRAY].sh_offset = dyn[i].d_un.d_ptr - 0x1000;
                shdr[INITARRAY].sh_addr = dyn[i].d_un.d_ptr;
                shdr[INITARRAY].sh_link = 0;
                shdr[INITARRAY].sh_info = 0;
                shdr[INITARRAY].sh_addralign = 4;
                shdr[INITARRAY].sh_entsize = 0;
                break;

            case DT_RELSZ:
                shdr[RELDYN].sh_size = dyn[i].d_un.d_val;
                break;

            case DT_STRSZ:
                shdr[DYNSTR].sh_size = dyn[i].d_un.d_val;
                break;

            case DT_PLTGOT:
                // 对.got 的区节头进行重建
                shdr[GOT].sh_name = strstr(str, ".got") - str;
                shdr[GOT].sh_type = SHT_PROGBITS;
                shdr[GOT].sh_flags = SHF_WRITE | SHF_ALLOC;
                shdr[GOT].sh_addr = shdr[DYNAMIC].sh_addr + shdr[DYNAMIC].sh_size;
                shdr[GOT].sh_offset = shdr[GOT].sh_addr - 0x1000;
                // 需要后面修正
                shdr[GOT].sh_size = dyn[i].d_un.d_ptr;
                shdr[GOT].sh_link = 0;
                shdr[GOT].sh_info = 0;
                shdr[GOT].sh_addralign = 4;
                shdr[GOT].sh_entsize = 0;
                break;
        }
    }
    // .got区节数据的大小
    shdr[GOT].sh_size = shdr[GOT].sh_size + 4 * (shdr[RELPLT].sh_size) / sizeof(Elf32_Rel) + 3 * sizeof(int) - shdr[GOT].sh_addr;

    //STRTAB地址 - SYMTAB地址 = SYMTAB大小
    shdr[DYNSYM].sh_size = shdr[DYNSTR].sh_addr - shdr[DYNSYM].sh_addr;

    shdr[FINIARRAY].sh_size = shdr[INITARRAY].sh_addr - shdr[FINIARRAY].sh_addr;
    shdr[INITARRAY].sh_size = shdr[DYNAMIC].sh_addr - shdr[INITARRAY].sh_addr;

    // 对.plt 的区节头进行重建
    shdr[PLT].sh_name = strstr(str, ".plt") - str;
    shdr[PLT].sh_type = SHT_PROGBITS;
    shdr[PLT].sh_flags = SHF_ALLOC | SHF_EXECINSTR;
    shdr[PLT].sh_addr = shdr[RELPLT].sh_addr + shdr[RELPLT].sh_size;
    shdr[PLT].sh_offset = shdr[PLT].sh_addr;
    shdr[PLT].sh_size = (20 + 12 * (shdr[RELPLT].sh_size) / sizeof(Elf32_Rel));
    shdr[PLT].sh_link = 0;
    shdr[PLT].sh_info = 0;
    shdr[PLT].sh_entsize = 0;
    shdr[PLT].sh_addralign = 4;

    // 对.text 的区节头进行重建( .text 与 .ARM.text 区节暂时无法分离开)
    shdr[TEXT].sh_name = strstr(str, ".text") - str;
    shdr[TEXT].sh_type = SHT_PROGBITS;
    shdr[TEXT].sh_flags = SHF_ALLOC | SHF_EXECINSTR;
    shdr[TEXT].sh_addr = shdr[PLT].sh_addr + shdr[PLT].sh_size;
    shdr[TEXT].sh_offset = shdr[TEXT].sh_addr;
    // 注意
    shdr[TEXT].sh_size = shdr[ARMEXIDX].sh_addr - shdr[TEXT].sh_addr;
    shdr[TEXT].sh_link = 0
    shdr[TEXT].sh_info = 0
    shdr[TEXT].sh_entsize = 0
    shdr[TEXT].sh_addralign = 4

    // 对.data 的区节头进行重建
    shdr[DATA].sh_name = strstr(str, ".data") - str;
    shdr[DATA].sh_type = SHT_PROGBITS;

    shdr[DATA].sh_flags = SHF_WRITE | SHF_ALLOC;
    shdr[DATA].sh_addr = shdr[GOT].sh_addr + shdr[GOT].sh_size;
    shdr[DATA].sh_offset = shdr[DATA].sh_addr - 0x1000;
    shdr[DATA].sh_size = load.p_vaddr + load.p_filesz - shdr[DATA].sh_addr;
    shdr[DATA].sh_link = 0
    shdr[DATA].sh_info = 0
    shdr[DATA].sh_entsize = 0
    shdr[DATA].sh_addralign = 4;

    // 对.shstrtab 区节头的重建
    shdr[STRTAB].sh_name = strstr(str, ".shstrtab") - str;
    shdr[STRTAB].sh_type = SHT_STRTAB;
    shdr[STRTAB].sh_flags = SHT_NULL;
    shdr[STRTAB].sh_addr = 0;
    shdr[STRTAB].sh_offset = shdr[BSS].sh_addr - 0x1000;
    shdr[STRTAB].sh_size = strlen(str) + 1;
    shdr[STRTAB].sh_link = 0;
    shdr[STRTAB].sh_info = 0;
    shdr[STRTAB].sh_entsize = 0;
    shdr[STRTAB].sh_addralign = 1;

    //memcpy(buffer + shdr[STRTAB].sh_offset, str, strlen(str));
    // 将ELF文件的区节头表信息拷贝到指定内存中
    memcpy(*sh_buffer, shdr, sizeof(shdr));
}

// main函数(ELF32的Android so的修复)
// 一个传入参数:需要修复的Android so文件路径
// 例如: needFix.so,修复后的so文件名称为fix.so
int main(int argc, char const *argv[])
{
    FILE* fr = NULL;
    long flen = 0;
    FILE* fw = NULL;
    int ph_len = 0;
    char* buffer = NULL;
    char* sh_buffer = NULL;
    Elf32_Ehdr *pehdr = NULL;
    Elf32_Phdr* pphdr = NULL;
    char arr[2048] = { 0 };

    // 传入参数检查
    if (argc < 2) {

        printf("less args\n");
        return;
    }

    // 打开需要修复的Android so文件
    fr = fopen(argv[1], "rb");
    if(fr == NULL) {

        printf("Open failed: \n");
        goto error;
    }

    // 获取需要修复的Android so文件的大小
    flen = get_file_len(fr);

    // 申请内存空间存放需要修复的Android so文件
    buffer = (char*)malloc(sizeof(char)*flen);
    if (buffer == NULL) {

        printf("Malloc error\n");
        goto error;
    }

    // 读取需要整个修复的Android so文件到申请的内存空间中
    size_t result = fread (buffer, 1, flen, fr);
    if (result != flen) {

        printf("Reading error\n");
        goto error;
    }

    // 创建新文件 fix.so 用于保存修复后的Android so
    fw = fopen("fix.so","wb");
    if(fw == NULL) {

        printf("Open failed: fix.so\n");
        goto error;
    }

    pehdr = (Elf32_Ehdr*)malloc(sizeof(Elf32_Ehdr));
    // 读取ELF文件的Elf32_Ehdr信息到申请的内存空间中
    get_elf_header(buffer, &pehdr);

    // 获取ELF文件的程序头Elf32_Phdr表的大小
    ph_len = pehdr->e_phentsize * pehdr->e_phnum;
    pphdr = (Elf32_Phdr*)malloc(ph_len);
    // 读取ELF文件的程序头表的信息到申请的内存空间中
    get_program_table(*pehdr, buffer, &pphdr);

    // 这个地方有一点问题
    // 申请内存到用于存放ELF文件的区节头表信息
    sh_buffer = (char* )malloc(pehdr->e_shentsize * pehdr->e_shnum);
    // 进行需要修复的Android so的区节头表的重建
    get_Info(pphdr, pehdr, buffer, &sh_buffer, pehdr->e_shentsize * pehdr->e_shnum);

    // 将重建后的ELF文件的区节头表信息进行回写和更正
    memcpy(buffer + pehdr->e_shoff, sh_buffer, pehdr->e_shentsize * pehdr->e_shnum);

    // 修复Android so文件的ELF文件头中关于节头表的信息
    pehdr->e_shnum = SHDRS;
    pehdr->e_shstrndx = SHDRS - 1;
    memcpy(buffer, pehdr, sizeof(Elf32_Ehdr));

    // SHSTRTAB
    // 新增.shstrtab 节数据到需要修复的Android so文件中
    memcpy(buffer + shdr[STRTAB].sh_offset, str1, strlen(str) + 1);

    // 将修复的信息更新写入到新的文件fix.so中
    fwrite(buffer, sizeof(char)*flen, 1, fw);

error:
    if(fw != NULL)
        fclose(fw);
    if(fr != NULL)
        fclose(fr);
    if(buffer != NULL)
        free(buffer);
    return 0;
}

头文件 elf.h 的代码如下:

#ifndef _QEMU_ELF_H
#define _QEMU_ELF_H
#include <inttypes.h>
/* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef int32_t  Elf32_Sword;
typedef uint32_t Elf32_Word;
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef int16_t     Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef int32_t     Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef int64_t  Elf64_Sxword;
/* These constants are for the segment types stored in the image headers */
#define PT_NULL    0
#define PT_LOAD    1
#define PT_DYNAMIC 2
#define PT_INTERP  3
#define PT_NOTE    4
#define PT_SHLIB   5
#define PT_PHDR    6
#define PT_LOPROC  0x70000000
#define PT_HIPROC  0x7fffffff
#define PT_MIPS_REGINFO    0x70000000
#define PT_MIPS_OPTIONS    0x70000001
/* Flags in the e_flags field of the header */
/* MIPS architecture level. */
#define EF_MIPS_ARCH_1    0x00000000  /* -mips1 code.  */
#define EF_MIPS_ARCH_2    0x10000000  /* -mips2 code.  */
#define EF_MIPS_ARCH_3    0x20000000  /* -mips3 code.  */
#define EF_MIPS_ARCH_4    0x30000000  /* -mips4 code.  */
#define EF_MIPS_ARCH_5    0x40000000  /* -mips5 code.  */
#define EF_MIPS_ARCH_32    0x50000000  /* MIPS32 code.  */
#define EF_MIPS_ARCH_64    0x60000000  /* MIPS64 code.  */
/* The ABI of a file. */
#define EF_MIPS_ABI_O32    0x00001000  /* O32 ABI.  */
#define EF_MIPS_ABI_O64    0x00002000  /* O32 extended for 64 bit.  */
#define EF_MIPS_NOREORDER 0x00000001
#define EF_MIPS_PIC       0x00000002
#define EF_MIPS_CPIC      0x00000004
#define EF_MIPS_ABI2    0x00000020
#define EF_MIPS_OPTIONS_FIRST    0x00000080
#define EF_MIPS_32BITMODE    0x00000100
#define EF_MIPS_ABI    0x0000f000
#define EF_MIPS_ARCH      0xf0000000
/* These constants define the different elf file types */
#define ET_NONE   0
#define ET_REL    1
#define ET_EXEC   2
#define ET_DYN    3
#define ET_CORE   4
#define ET_LOPROC 0xff00
#define ET_HIPROC 0xffff
/* These constants define the various ELF target machines */
#define EM_NONE  0
#define EM_M32   1
#define EM_SPARC 2
#define EM_386   3
#define EM_68K   4
#define EM_88K   5
#define EM_486   6   /* Perhaps disused */
#define EM_860   7
#define EM_MIPS    8   /* MIPS R3000 (officially, big-endian only) */
#define EM_MIPS_RS4_BE 10    /* MIPS R4000 big-endian */
#define EM_PARISC      15    /* HPPA */
#define EM_SPARC32PLUS 18    /* Sun's "v8plus" */
#define EM_PPC           20   /* PowerPC */
#define EM_PPC64       21       /* PowerPC64 */
#define EM_ARM    40  /* ARM */
#define EM_SH           42   /* SuperH */
#define EM_SPARCV9     43    /* SPARC v9 64-bit */
#define EM_IA_64    50  /* HP/Intel IA-64 */
#define EM_X86_64    62  /* AMD x86-64 */
#define EM_S390    22  /* IBM S/390 */
#define EM_CRIS         76      /* Axis Communications 32-bit embedded processor */
#define EM_V850    87  /* NEC v850 */
#define EM_H8_300H      47      /* Hitachi H8/300H */
#define EM_H8S          48      /* Hitachi H8S     */
/*
 * This is an interim value that we will use until the committee comes
 * up with a final number.
 */
#define EM_ALPHA    0x9026
/* Bogus old v850 magic number, used by old tools.  */
#define EM_CYGNUS_V850    0x9080
/*
 * This is the old interim value for S/390 architecture
 */
#define EM_S390_OLD     0xA390
/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL    0
#define DT_NEEDED    1
#define DT_PLTRELSZ    2
#define DT_PLTGOT    3
#define DT_HASH        4
#define DT_STRTAB    5
#define DT_SYMTAB    6
#define DT_RELA        7
#define DT_RELASZ    8
#define DT_RELAENT    9
#define DT_STRSZ    10
#define DT_SYMENT    11
#define DT_INIT        25
#define DT_FINI        26
#define DT_SONAME    14
#define DT_RPATH     15
#define DT_SYMBOLIC    16
#define DT_REL        17
#define DT_RELSZ    18
#define DT_RELENT    19
#define DT_PLTREL    20
#define DT_DEBUG    21
#define DT_TEXTREL    22
#define DT_JMPREL    23
#define DT_LOPROC    0x70000000
#define DT_HIPROC    0x7fffffff
#define DT_MIPS_RLD_VERSION    0x70000001
#define DT_MIPS_TIME_STAMP    0x70000002
#define DT_MIPS_ICHECKSUM    0x70000003
#define DT_MIPS_IVERSION    0x70000004
#define DT_MIPS_FLAGS    0x70000005
#define RHF_NONE      0
#define RHF_HARDWAY      1
#define RHF_NOTPOT      2
#define DT_MIPS_BASE_ADDRESS    0x70000006
#define DT_MIPS_CONFLICT    0x70000008
#define DT_MIPS_LIBLIST    0x70000009
#define DT_MIPS_LOCAL_GOTNO    0x7000000a
#define DT_MIPS_CONFLICTNO    0x7000000b
#define DT_MIPS_LIBLISTNO    0x70000010
#define DT_MIPS_SYMTABNO    0x70000011
#define DT_MIPS_UNREFEXTNO    0x70000012
#define DT_MIPS_GOTSYM    0x70000013
#define DT_MIPS_HIPAGENO    0x70000014
#define DT_MIPS_RLD_MAP    0x70000016
/* This info is needed when parsing the symbol table */
#define STB_LOCAL  0
#define STB_GLOBAL 1
#define STB_WEAK   2
#define STT_NOTYPE  0
#define STT_OBJECT  1
#define STT_FUNC    2
#define STT_SECTION 3
#define STT_FILE    4
#define ELF_ST_BIND(x)    ((x) >> 4)
#define ELF_ST_TYPE(x)    (((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x)    ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x)    ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x)    ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x)    ELF_ST_TYPE(x)
/* Symbolic values for the entries in the auxiliary table
   put on the initial stack */
#define AT_NULL   0    /* end of vector */
#define AT_IGNORE 1    /* entry should be ignored */
#define AT_EXECFD 2    /* file descriptor of program */
#define AT_PHDR   3    /* program headers for program */
#define AT_PHENT  4    /* size of program header entry */
#define AT_PHNUM  5    /* number of program headers */
#define AT_PAGESZ 6    /* system page size */
#define AT_BASE   7    /* base address of interpreter */
#define AT_FLAGS  8    /* flags */
#define AT_ENTRY  9    /* entry point of program */
#define AT_NOTELF 10    /* program is not ELF */
#define AT_UID    11    /* real uid */
#define AT_EUID   12    /* effective uid */
#define AT_GID    13    /* real gid */
#define AT_EGID   14    /* effective gid */
#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17    /* frequency at which times() increments */

typedef struct dynamic{
  Elf32_Sword d_tag;
  union{
    Elf32_Sword    d_val;
    Elf32_Addr    d_ptr;
  } d_un;
} Elf32_Dyn;
typedef struct {
  Elf64_Sxword d_tag;    /* entry tag value */
  union {
    Elf64_Xword d_val;
    Elf64_Addr d_ptr;
  } d_un;
} Elf64_Dyn;

/* The following are used with relocations */
#define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff)
#define ELF64_R_SYM(i)    ((i) >> 32)
#define ELF64_R_TYPE(i)    ((i) & 0xffffffff)
#define ELF64_R_TYPE_DATA(i)            (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
#define R_386_NONE    0
#define R_386_32    1
#define R_386_PC32    2
#define R_386_GOT32    3
#define R_386_PLT32    4
#define R_386_COPY    5
#define R_386_GLOB_DAT    6
#define R_386_JMP_SLOT    7
#define R_386_RELATIVE    8
#define R_386_GOTOFF    9
#define R_386_GOTPC    10
#define R_386_NUM    11
#define R_MIPS_NONE    0
#define R_MIPS_16    1
#define R_MIPS_32    2
#define R_MIPS_REL32    3
#define R_MIPS_26    4
#define R_MIPS_HI16    5
#define R_MIPS_LO16    6
#define R_MIPS_GPREL16    7
#define R_MIPS_LITERAL    8
#define R_MIPS_GOT16    9
#define R_MIPS_PC16    10
#define R_MIPS_CALL16    11
#define R_MIPS_GPREL32    12
/* The remaining relocs are defined on Irix, although they are not
   in the MIPS ELF ABI.  */
#define R_MIPS_UNUSED1    13
#define R_MIPS_UNUSED2    14
#define R_MIPS_UNUSED3    15
#define R_MIPS_SHIFT5    16
#define R_MIPS_SHIFT6    17
#define R_MIPS_64    18
#define R_MIPS_GOT_DISP    19
#define R_MIPS_GOT_PAGE    20
#define R_MIPS_GOT_OFST    21
/*
 * The following two relocation types are specified in the MIPS ABI
 * conformance guide version 1.2 but not yet in the psABI.
 */
#define R_MIPS_GOTHI16    22
#define R_MIPS_GOTLO16    23
#define R_MIPS_SUB    24
#define R_MIPS_INSERT_A    25
#define R_MIPS_INSERT_B    26
#define R_MIPS_DELETE    27
#define R_MIPS_HIGHER    28
#define R_MIPS_HIGHEST    29
/*
 * The following two relocation types are specified in the MIPS ABI
 * conformance guide version 1.2 but not yet in the psABI.
 */
#define R_MIPS_CALLHI16    30
#define R_MIPS_CALLLO16    31
/*
 * This range is reserved for vendor specific relocations.
 */
#define R_MIPS_LOVENDOR    100
#define R_MIPS_HIVENDOR    127
/*
 * Sparc ELF relocation types
 */
#define    R_SPARC_NONE    0
#define    R_SPARC_8   1
#define    R_SPARC_16  2
#define    R_SPARC_32  3
#define    R_SPARC_DISP8   4
#define    R_SPARC_DISP16  5
#define    R_SPARC_DISP32  6
#define    R_SPARC_WDISP30 7
#define    R_SPARC_WDISP22 8
#define    R_SPARC_HI22    9
#define    R_SPARC_22  10
#define    R_SPARC_13  11
#define    R_SPARC_LO10    12
#define    R_SPARC_GOT10   13
#define    R_SPARC_GOT13   14
#define    R_SPARC_GOT22   15
#define    R_SPARC_PC10    16
#define    R_SPARC_PC22    17
#define    R_SPARC_WPLT30  18
#define    R_SPARC_COPY    19
#define    R_SPARC_GLOB_DAT    20
#define    R_SPARC_JMP_SLOT    21
#define    R_SPARC_RELATIVE    22
#define    R_SPARC_UA32    23
#define R_SPARC_PLT32    24
#define R_SPARC_HIPLT22    25
#define R_SPARC_LOPLT10    26
#define R_SPARC_PCPLT32    27
#define R_SPARC_PCPLT22    28
#define R_SPARC_PCPLT10    29
#define R_SPARC_10    30
#define R_SPARC_11    31
#define R_SPARC_64    32
#define R_SPARC_OLO10           33
#define R_SPARC_HH22            34
#define R_SPARC_HM10            35
#define R_SPARC_LM22            36
#define R_SPARC_WDISP16    40
#define R_SPARC_WDISP19    41
#define R_SPARC_7    43
#define R_SPARC_5    44
#define R_SPARC_6    45
/* Bits present in AT_HWCAP, primarily for Sparc32.  */
#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
#define HWCAP_SPARC_STBAR       2
#define HWCAP_SPARC_SWAP        4
#define HWCAP_SPARC_MULDIV      8
#define HWCAP_SPARC_V9    16
#define HWCAP_SPARC_ULTRA3    32
/*
 * 68k ELF relocation types
 */
#define R_68K_NONE    0
#define R_68K_32    1
#define R_68K_16    2
#define R_68K_8    3
#define R_68K_PC32    4
#define R_68K_PC16    5
#define R_68K_PC8    6
#define R_68K_GOT32    7
#define R_68K_GOT16    8
#define R_68K_GOT8    9
#define R_68K_GOT32O    10
#define R_68K_GOT16O    11
#define R_68K_GOT8O    12
#define R_68K_PLT32    13
#define R_68K_PLT16    14
#define R_68K_PLT8    15
#define R_68K_PLT32O    16
#define R_68K_PLT16O    17
#define R_68K_PLT8O    18
#define R_68K_COPY    19
#define R_68K_GLOB_DAT    20
#define R_68K_JMP_SLOT    21
#define R_68K_RELATIVE    22
/*
 * Alpha ELF relocation types
 */
#define R_ALPHA_NONE            0       /* No reloc */
#define R_ALPHA_REFLONG         1       /* Direct 32 bit */
#define R_ALPHA_REFQUAD         2       /* Direct 64 bit */
#define R_ALPHA_GPREL32         3       /* GP relative 32 bit */
#define R_ALPHA_LITERAL         4       /* GP relative 16 bit w/optimization */
#define R_ALPHA_LITUSE          5       /* Optimization hint for LITERAL */
#define R_ALPHA_GPDISP          6       /* Add displacement to GP */
#define R_ALPHA_BRADDR          7       /* PC+4 relative 23 bit shifted */
#define R_ALPHA_HINT            8       /* PC+4 relative 16 bit shifted */
#define R_ALPHA_SREL16          9       /* PC relative 16 bit */
#define R_ALPHA_SREL32          10      /* PC relative 32 bit */
#define R_ALPHA_SREL64          11      /* PC relative 64 bit */
#define R_ALPHA_GPRELHIGH       17      /* GP relative 32 bit, high 16 bits */
#define R_ALPHA_GPRELLOW        18      /* GP relative 32 bit, low 16 bits */
#define R_ALPHA_GPREL16         19      /* GP relative 16 bit */
#define R_ALPHA_COPY            24      /* Copy symbol at runtime */
#define R_ALPHA_GLOB_DAT        25      /* Create GOT entry */
#define R_ALPHA_JMP_SLOT        26      /* Create PLT entry */
#define R_ALPHA_RELATIVE        27      /* Adjust by program base */
#define R_ALPHA_BRSGP    28
#define R_ALPHA_TLSGD           29
#define R_ALPHA_TLS_LDM         30
#define R_ALPHA_DTPMOD64        31
#define R_ALPHA_GOTDTPREL       32
#define R_ALPHA_DTPREL64        33
#define R_ALPHA_DTPRELHI        34
#define R_ALPHA_DTPRELLO        35
#define R_ALPHA_DTPREL16        36
#define R_ALPHA_GOTTPREL        37
#define R_ALPHA_TPREL64         38
#define R_ALPHA_TPRELHI         39
#define R_ALPHA_TPRELLO         40
#define R_ALPHA_TPREL16         41
#define SHF_ALPHA_GPREL    0x10000000
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE    0
#define R_PPC_ADDR32    1   /* 32bit absolute address */
#define R_PPC_ADDR24    2   /* 26bit address, 2 bits ignored.  */
#define R_PPC_ADDR16    3   /* 16bit absolute address */
#define R_PPC_ADDR16_LO    4   /* lower 16bit of absolute address */
#define R_PPC_ADDR16_HI    5   /* high 16bit of absolute address */
#define R_PPC_ADDR16_HA    6   /* adjusted high 16bit */
#define R_PPC_ADDR14    7   /* 16bit address, 2 bits ignored */
#define R_PPC_ADDR14_BRTAKEN    8
#define R_PPC_ADDR14_BRNTAKEN    9
#define R_PPC_REL24    10  /* PC relative 26 bit */
#define R_PPC_REL14    11  /* PC relative 16 bit */
#define R_PPC_REL14_BRTAKEN    12
#define R_PPC_REL14_BRNTAKEN    13
#define R_PPC_GOT16    14
#define R_PPC_GOT16_LO    15
#define R_PPC_GOT16_HI    16
#define R_PPC_GOT16_HA    17
#define R_PPC_PLTREL24    18
#define R_PPC_COPY    19
#define R_PPC_GLOB_DAT    20
#define R_PPC_JMP_SLOT    21
#define R_PPC_RELATIVE    22
#define R_PPC_LOCAL24PC    23
#define R_PPC_UADDR32    24
#define R_PPC_UADDR16    25
#define R_PPC_REL32    26
#define R_PPC_PLT32    27
#define R_PPC_PLTREL32    28
#define R_PPC_PLT16_LO    29
#define R_PPC_PLT16_HI    30
#define R_PPC_PLT16_HA    31
#define R_PPC_SDAREL16    32
#define R_PPC_SECTOFF    33
#define R_PPC_SECTOFF_LO    34
#define R_PPC_SECTOFF_HI    35
#define R_PPC_SECTOFF_HA    36
/* Keep this the last entry.  */
#define R_PPC_NUM    37
/* ARM specific declarations */
/* Processor specific flags for the ELF header e_flags field.  */
#define EF_ARM_RELEXEC     0x01
#define EF_ARM_HASENTRY    0x02
#define EF_ARM_INTERWORK   0x04
#define EF_ARM_APCS_26     0x08
#define EF_ARM_APCS_FLOAT  0x10
#define EF_ARM_PIC         0x20
#define EF_ALIGN8          0x40    /* 8-bit structure alignment is in use */
#define EF_NEW_ABI         0x80
#define EF_OLD_ABI         0x100
/* Additional symbol types for Thumb */
#define STT_ARM_TFUNC      0xd
/* ARM-specific values for sh_flags */
#define SHF_ARM_ENTRYSECT  0x10000000   /* Section contains an entry point */
#define SHF_ARM_COMDEF     0x80000000   /* Section may be multiply defined
   in the input to a link step */
/* ARM-specific program header flags */
#define PF_ARM_SB          0x10000000   /* Segment contains the location
   addressed by the static base */
/* ARM relocs.  */
#define R_ARM_NONE    0   /* No reloc */
#define R_ARM_PC24    1   /* PC relative 26 bit branch */
#define R_ARM_ABS32    2   /* Direct 32 bit  */
#define R_ARM_REL32    3   /* PC relative 32 bit */
#define R_ARM_PC13    4
#define R_ARM_ABS16    5   /* Direct 16 bit */
#define R_ARM_ABS12    6   /* Direct 12 bit */
#define R_ARM_THM_ABS5    7
#define R_ARM_ABS8    8   /* Direct 8 bit */
#define R_ARM_SBREL32    9
#define R_ARM_THM_PC22    10
#define R_ARM_THM_PC8    11
#define R_ARM_AMP_VCALL9    12
#define R_ARM_SWI24    13
#define R_ARM_THM_SWI8    14
#define R_ARM_XPC25    15
#define R_ARM_THM_XPC22    16
#define R_ARM_COPY    20  /* Copy symbol at runtime */
#define R_ARM_GLOB_DAT    21  /* Create GOT entry */
#define R_ARM_JUMP_SLOT    22  /* Create PLT entry */
#define R_ARM_RELATIVE    23  /* Adjust by program base */
#define R_ARM_GOTOFF    24  /* 32 bit offset to GOT */
#define R_ARM_GOTPC    25  /* 32 bit PC relative offset to GOT */
#define R_ARM_GOT32    26  /* 32 bit GOT entry */
#define R_ARM_PLT32    27  /* 32 bit PLT address */
#define R_ARM_CALL              28
#define R_ARM_JUMP24            29
#define R_ARM_GNU_VTENTRY    100
#define R_ARM_GNU_VTINHERIT    101
#define R_ARM_THM_PC11    102 /* thumb unconditional branch */
#define R_ARM_THM_PC9    103 /* thumb conditional branch */
#define R_ARM_RXPC25    249
#define R_ARM_RSBREL32    250
#define R_ARM_THM_RPC22    251
#define R_ARM_RREL32    252
#define R_ARM_RABS22    253
#define R_ARM_RPC24    254
#define R_ARM_RBASE    255
/* Keep this the last entry.  */
#define R_ARM_NUM    256
/* s390 relocations defined by the ABIs */
#define R_390_NONE    0   /* No reloc.  */
#define R_390_8    1   /* Direct 8 bit.  */
#define R_390_12    2   /* Direct 12 bit.  */
#define R_390_16    3   /* Direct 16 bit.  */
#define R_390_32    4   /* Direct 32 bit.  */
#define R_390_PC32    5   /* PC relative 32 bit.  */
#define R_390_GOT12    6   /* 12 bit GOT offset.  */
#define R_390_GOT32    7   /* 32 bit GOT offset.  */
#define R_390_PLT32    8   /* 32 bit PC relative PLT address.  */
#define R_390_COPY    9   /* Copy symbol at runtime.  */
#define R_390_GLOB_DAT    10  /* Create GOT entry.  */
#define R_390_JMP_SLOT    11  /* Create PLT entry.  */
#define R_390_RELATIVE    12  /* Adjust by program base.  */
#define R_390_GOTOFF32    13  /* 32 bit offset to GOT.     */
#define R_390_GOTPC    14  /* 32 bit PC rel. offset to GOT.  */
#define R_390_GOT16    15  /* 16 bit GOT offset.  */
#define R_390_PC16    16  /* PC relative 16 bit.  */
#define R_390_PC16DBL    17  /* PC relative 16 bit shifted by 1.  */
#define R_390_PLT16DBL    18  /* 16 bit PC rel. PLT shifted by 1.  */
#define R_390_PC32DBL    19  /* PC relative 32 bit shifted by 1.  */
#define R_390_PLT32DBL    20  /* 32 bit PC rel. PLT shifted by 1.  */
#define R_390_GOTPCDBL    21  /* 32 bit PC rel. GOT shifted by 1.  */
#define R_390_64    22  /* Direct 64 bit.  */
#define R_390_PC64    23  /* PC relative 64 bit.  */
#define R_390_GOT64    24  /* 64 bit GOT offset.  */
#define R_390_PLT64    25  /* 64 bit PC relative PLT address.  */
#define R_390_GOTENT    26  /* 32 bit PC rel. to GOT entry >> 1. */
#define R_390_GOTOFF16    27  /* 16 bit offset to GOT. */
#define R_390_GOTOFF64    28  /* 64 bit offset to GOT. */
#define R_390_GOTPLT12    29  /* 12 bit offset to jump slot.  */
#define R_390_GOTPLT16    30  /* 16 bit offset to jump slot.  */
#define R_390_GOTPLT32    31  /* 32 bit offset to jump slot.  */
#define R_390_GOTPLT64    32  /* 64 bit offset to jump slot.  */
#define R_390_GOTPLTENT    33  /* 32 bit rel. offset to jump slot.  */
#define R_390_PLTOFF16    34  /* 16 bit offset from GOT to PLT. */
#define R_390_PLTOFF32    35  /* 32 bit offset from GOT to PLT. */
#define R_390_PLTOFF64    36  /* 16 bit offset from GOT to PLT. */
#define R_390_TLS_LOAD    37  /* Tag for load insn in TLS code. */
#define R_390_TLS_GDCALL    38  /* Tag for function call in general
                                           dynamic TLS code.  */
#define R_390_TLS_LDCALL    39  /* Tag for function call in local
                                           dynamic TLS code.  */
#define R_390_TLS_GD32    40  /* Direct 32 bit for general dynamic
                                           thread local data.  */
#define R_390_TLS_GD64    41  /* Direct 64 bit for general dynamic
                                           thread local data.  */
#define R_390_TLS_GOTIE12    42  /* 12 bit GOT offset for static TLS
                                           block offset.  */
#define R_390_TLS_GOTIE32    43  /* 32 bit GOT offset for static TLS
                                           block offset.  */
#define R_390_TLS_GOTIE64    44  /* 64 bit GOT offset for static TLS
                                           block offset.  */
#define R_390_TLS_LDM32    45  /* Direct 32 bit for local dynamic
                                           thread local data in LD code.  */
#define R_390_TLS_LDM64    46  /* Direct 64 bit for local dynamic
                                           thread local data in LD code.  */
#define R_390_TLS_IE32    47  /* 32 bit address of GOT entry for
                                           negated static TLS block offset.  */
#define R_390_TLS_IE64    48  /* 64 bit address of GOT entry for
                                           negated static TLS block offset.  */
#define R_390_TLS_IEENT    49  /* 32 bit rel. offset to GOT entry for
                                           negated static TLS block offset.  */
#define R_390_TLS_LE32    50  /* 32 bit negated offset relative to
                                           static TLS block.  */
#define R_390_TLS_LE64    51  /* 64 bit negated offset relative to
                                           static TLS block.  */
#define R_390_TLS_LDO32    52  /* 32 bit offset relative to TLS
                                           block.  */
#define R_390_TLS_LDO64    53  /* 64 bit offset relative to TLS
                                           block.  */
#define R_390_TLS_DTPMOD    54  /* ID of module containing symbol.  */
#define R_390_TLS_DTPOFF    55  /* Offset in TLS block.  */
#define R_390_TLS_TPOFF    56  /* Negate offset in static TLS
                                           block.  */
/* Keep this the last entry.  */
#define R_390_NUM    57
/* x86-64 relocation types */
#define R_X86_64_NONE    0   /* No reloc */
#define R_X86_64_64    1   /* Direct 64 bit  */
#define R_X86_64_PC32    2   /* PC relative 32 bit signed */
#define R_X86_64_GOT32    3   /* 32 bit GOT entry */
#define R_X86_64_PLT32    4   /* 32 bit PLT address */
#define R_X86_64_COPY    5   /* Copy symbol at runtime */
#define R_X86_64_GLOB_DAT    6   /* Create GOT entry */
#define R_X86_64_JUMP_SLOT    7   /* Create PLT entry */
#define R_X86_64_RELATIVE    8   /* Adjust by program base */
#define R_X86_64_GOTPCREL    9   /* 32 bit signed pc relative
   offset to GOT */
#define R_X86_64_32    10  /* Direct 32 bit zero extended */
#define R_X86_64_32S    11  /* Direct 32 bit sign extended */
#define R_X86_64_16    12  /* Direct 16 bit zero extended */
#define R_X86_64_PC16    13  /* 16 bit sign extended pc relative */
#define R_X86_64_8    14  /* Direct 8 bit sign extended  */
#define R_X86_64_PC8    15  /* 8 bit sign extended pc relative */
#define R_X86_64_NUM    16
/* Legal values for e_flags field of Elf64_Ehdr.  */
#define EF_ALPHA_32BIT    1   /* All addresses are below 2GB */
/* HPPA specific definitions.  */
/* Legal values for e_flags field of Elf32_Ehdr.  */
#define EF_PARISC_TRAPNIL    0x00010000 /* Trap nil pointer dereference.  */
#define EF_PARISC_EXT    0x00020000 /* Program uses arch. extensions. */
#define EF_PARISC_LSB    0x00040000 /* Program expects little endian. */
#define EF_PARISC_WIDE    0x00080000 /* Program expects wide mode.  */
#define EF_PARISC_NO_KABP    0x00100000 /* No kernel assisted branch
      prediction.  */
#define EF_PARISC_LAZYSWAP    0x00400000 /* Allow lazy swapping.  */
#define EF_PARISC_ARCH    0x0000ffff /* Architecture version.  */
/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
#define EFA_PARISC_1_0        0x020b /* PA-RISC 1.0 big-endian.  */
#define EFA_PARISC_1_1        0x0210 /* PA-RISC 1.1 big-endian.  */
#define EFA_PARISC_2_0        0x0214 /* PA-RISC 2.0 big-endian.  */
/* Additional section indeces.  */
#define SHN_PARISC_ANSI_COMMON    0xff00     /* Section for tenatively declared
      symbols in ANSI C.  */
#define SHN_PARISC_HUGE_COMMON    0xff01     /* Common blocks in huge model.  */
/* Legal values for sh_type field of Elf32_Shdr.  */
#define SHT_PARISC_EXT    0x70000000 /* Contains product specific ext. */
#define SHT_PARISC_UNWIND    0x70000001 /* Unwind information.  */
#define SHT_PARISC_DOC    0x70000002 /* Debug info for optimized code. */
/* Legal values for sh_flags field of Elf32_Shdr.  */
#define SHF_PARISC_SHORT    0x20000000 /* Section with short addressing. */
#define SHF_PARISC_HUGE    0x40000000 /* Section far from gp.  */
#define SHF_PARISC_SBP    0x80000000 /* Static branch prediction code. */
/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
#define STT_PARISC_MILLICODE    13  /* Millicode function entry point.  */
#define STT_HP_OPAQUE    (STT_LOOS + 0x1)
#define STT_HP_STUB    (STT_LOOS + 0x2)
/* HPPA relocs.  */
#define R_PARISC_NONE    0   /* No reloc.  */
#define R_PARISC_DIR32    1   /* Direct 32-bit reference.  */
#define R_PARISC_DIR21L    2   /* Left 21 bits of eff. address.  */
#define R_PARISC_DIR17R    3   /* Right 17 bits of eff. address.  */
#define R_PARISC_DIR17F    4   /* 17 bits of eff. address.  */
#define R_PARISC_DIR14R    6   /* Right 14 bits of eff. address.  */
#define R_PARISC_PCREL32    9   /* 32-bit rel. address.  */
#define R_PARISC_PCREL21L    10  /* Left 21 bits of rel. address.  */
#define R_PARISC_PCREL17R    11  /* Right 17 bits of rel. address.  */
#define R_PARISC_PCREL17F    12  /* 17 bits of rel. address.  */
#define R_PARISC_PCREL14R    14  /* Right 14 bits of rel. address.  */
#define R_PARISC_DPREL21L    18  /* Left 21 bits of rel. address.  */
#define R_PARISC_DPREL14R    22  /* Right 14 bits of rel. address.  */
#define R_PARISC_GPREL21L    26  /* GP-relative, left 21 bits.  */
#define R_PARISC_GPREL14R    30  /* GP-relative, right 14 bits.  */
#define R_PARISC_LTOFF21L    34  /* LT-relative, left 21 bits.  */
#define R_PARISC_LTOFF14R    38  /* LT-relative, right 14 bits.  */
#define R_PARISC_SECREL32    41  /* 32 bits section rel. address.  */
#define R_PARISC_SEGBASE    48  /* No relocation, set segment base.  */
#define R_PARISC_SEGREL32    49  /* 32 bits segment rel. address.  */
#define R_PARISC_PLTOFF21L    50  /* PLT rel. address, left 21 bits.  */
#define R_PARISC_PLTOFF14R    54  /* PLT rel. address, right 14 bits.  */
#define R_PARISC_LTOFF_FPTR32    57  /* 32 bits LT-rel. function pointer. */
#define R_PARISC_LTOFF_FPTR21L    58  /* LT-rel. fct ptr, left 21 bits. */
#define R_PARISC_LTOFF_FPTR14R    62  /* LT-rel. fct ptr, right 14 bits. */
#define R_PARISC_FPTR64    64  /* 64 bits function address.  */
#define R_PARISC_PLABEL32    65  /* 32 bits function address.  */
#define R_PARISC_PCREL64    72  /* 64 bits PC-rel. address.  */
#define R_PARISC_PCREL22F    74  /* 22 bits PC-rel. address.  */
#define R_PARISC_PCREL14WR    75  /* PC-rel. address, right 14 bits.  */
#define R_PARISC_PCREL14DR    76  /* PC rel. address, right 14 bits.  */
#define R_PARISC_PCREL16F    77  /* 16 bits PC-rel. address.  */
#define R_PARISC_PCREL16WF    78  /* 16 bits PC-rel. address.  */
#define R_PARISC_PCREL16DF    79  /* 16 bits PC-rel. address.  */
#define R_PARISC_DIR64    80  /* 64 bits of eff. address.  */
#define R_PARISC_DIR14WR    83  /* 14 bits of eff. address.  */
#define R_PARISC_DIR14DR    84  /* 14 bits of eff. address.  */
#define R_PARISC_DIR16F    85  /* 16 bits of eff. address.  */
#define R_PARISC_DIR16WF    86  /* 16 bits of eff. address.  */
#define R_PARISC_DIR16DF    87  /* 16 bits of eff. address.  */
#define R_PARISC_GPREL64    88  /* 64 bits of GP-rel. address.  */
#define R_PARISC_GPREL14WR    91  /* GP-rel. address, right 14 bits.  */
#define R_PARISC_GPREL14DR    92  /* GP-rel. address, right 14 bits.  */
#define R_PARISC_GPREL16F    93  /* 16 bits GP-rel. address.  */
#define R_PARISC_GPREL16WF    94  /* 16 bits GP-rel. address.  */
#define R_PARISC_GPREL16DF    95  /* 16 bits GP-rel. address.  */
#define R_PARISC_LTOFF64    96  /* 64 bits LT-rel. address.  */
#define R_PARISC_LTOFF14WR    99  /* LT-rel. address, right 14 bits.  */
#define R_PARISC_LTOFF14DR    100 /* LT-rel. address, right 14 bits.  */
#define R_PARISC_LTOFF16F    101 /* 16 bits LT-rel. address.  */
#define R_PARISC_LTOFF16WF    102 /* 16 bits LT-rel. address.  */
#define R_PARISC_LTOFF16DF    103 /* 16 bits LT-rel. address.  */
#define R_PARISC_SECREL64    104 /* 64 bits section rel. address.  */
#define R_PARISC_SEGREL64    112 /* 64 bits segment rel. address.  */
#define R_PARISC_PLTOFF14WR    115 /* PLT-rel. address, right 14 bits.  */
#define R_PARISC_PLTOFF14DR    116 /* PLT-rel. address, right 14 bits.  */
#define R_PARISC_PLTOFF16F    117 /* 16 bits LT-rel. address.  */
#define R_PARISC_PLTOFF16WF    118 /* 16 bits PLT-rel. address.  */
#define R_PARISC_PLTOFF16DF    119 /* 16 bits PLT-rel. address.  */
#define R_PARISC_LTOFF_FPTR64    120 /* 64 bits LT-rel. function ptr.  */
#define R_PARISC_LTOFF_FPTR14WR    123 /* LT-rel. fct. ptr., right 14 bits. */
#define R_PARISC_LTOFF_FPTR14DR    124 /* LT-rel. fct. ptr., right 14 bits. */
#define R_PARISC_LTOFF_FPTR16F    125 /* 16 bits LT-rel. function ptr.  */
#define R_PARISC_LTOFF_FPTR16WF    126 /* 16 bits LT-rel. function ptr.  */
#define R_PARISC_LTOFF_FPTR16DF    127 /* 16 bits LT-rel. function ptr.  */
#define R_PARISC_LORESERVE    128
#define R_PARISC_COPY    128 /* Copy relocation.  */
#define R_PARISC_IPLT    129 /* Dynamic reloc, imported PLT */
#define R_PARISC_EPLT    130 /* Dynamic reloc, exported PLT */
#define R_PARISC_TPREL32    153 /* 32 bits TP-rel. address.  */
#define R_PARISC_TPREL21L    154 /* TP-rel. address, left 21 bits.  */
#define R_PARISC_TPREL14R    158 /* TP-rel. address, right 14 bits.  */
#define R_PARISC_LTOFF_TP21L    162 /* LT-TP-rel. address, left 21 bits. */
#define R_PARISC_LTOFF_TP14R    166 /* LT-TP-rel. address, right 14 bits.*/
#define R_PARISC_LTOFF_TP14F    167 /* 14 bits LT-TP-rel. address.  */
#define R_PARISC_TPREL64    216 /* 64 bits TP-rel. address.  */
#define R_PARISC_TPREL14WR    219 /* TP-rel. address, right 14 bits.  */
#define R_PARISC_TPREL14DR    220 /* TP-rel. address, right 14 bits.  */
#define R_PARISC_TPREL16F    221 /* 16 bits TP-rel. address.  */
#define R_PARISC_TPREL16WF    222 /* 16 bits TP-rel. address.  */
#define R_PARISC_TPREL16DF    223 /* 16 bits TP-rel. address.  */
#define R_PARISC_LTOFF_TP64    224 /* 64 bits LT-TP-rel. address.  */
#define R_PARISC_LTOFF_TP14WR    227 /* LT-TP-rel. address, right 14 bits.*/
#define R_PARISC_LTOFF_TP14DR    228 /* LT-TP-rel. address, right 14 bits.*/
#define R_PARISC_LTOFF_TP16F    229 /* 16 bits LT-TP-rel. address.  */
#define R_PARISC_LTOFF_TP16WF    230 /* 16 bits LT-TP-rel. address.  */
#define R_PARISC_LTOFF_TP16DF    231 /* 16 bits LT-TP-rel. address.  */
#define R_PARISC_HIRESERVE    255
/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
#define PT_HP_TLS    (PT_LOOS + 0x0)
#define PT_HP_CORE_NONE    (PT_LOOS + 0x1)
#define PT_HP_CORE_VERSION    (PT_LOOS + 0x2)
#define PT_HP_CORE_KERNEL    (PT_LOOS + 0x3)
#define PT_HP_CORE_COMM    (PT_LOOS + 0x4)
#define PT_HP_CORE_PROC    (PT_LOOS + 0x5)
#define PT_HP_CORE_LOADABLE    (PT_LOOS + 0x6)
#define PT_HP_CORE_STACK    (PT_LOOS + 0x7)
#define PT_HP_CORE_SHM    (PT_LOOS + 0x8)
#define PT_HP_CORE_MMF    (PT_LOOS + 0x9)
#define PT_HP_PARALLEL    (PT_LOOS + 0x10)
#define PT_HP_FASTBIND    (PT_LOOS + 0x11)
#define PT_HP_OPT_ANNOT    (PT_LOOS + 0x12)
#define PT_HP_HSL_ANNOT    (PT_LOOS + 0x13)
#define PT_HP_STACK    (PT_LOOS + 0x14)
#define PT_PARISC_ARCHEXT    0x70000000
#define PT_PARISC_UNWIND    0x70000001
/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
#define PF_PARISC_SBP    0x08000000
#define PF_HP_PAGE_SIZE    0x00100000
#define PF_HP_FAR_SHARED    0x00200000
#define PF_HP_NEAR_SHARED    0x00400000
#define PF_HP_CODE    0x01000000
#define PF_HP_MODIFY    0x02000000
#define PF_HP_LAZYSWAP    0x04000000
#define PF_HP_SBP    0x08000000
/* IA-64 specific declarations.  */
/* Processor specific flags for the Ehdr e_flags field.  */
#define EF_IA_64_MASKOS    0x0000000f  /* os-specific flags */
#define EF_IA_64_ABI64    0x00000010  /* 64-bit ABI */
#define EF_IA_64_ARCH    0xff000000  /* arch. version mask */
/* Processor specific values for the Phdr p_type field.  */
#define PT_IA_64_ARCHEXT    (PT_LOPROC + 0) /* arch extension bits */
#define PT_IA_64_UNWIND    (PT_LOPROC + 1) /* ia64 unwind bits */
/* Processor specific flags for the Phdr p_flags field.  */
#define PF_IA_64_NORECOV    0x80000000  /* spec insns w/o recovery */
/* Processor specific values for the Shdr sh_type field.  */
#define SHT_IA_64_EXT    (SHT_LOPROC + 0) /* extension bits */
#define SHT_IA_64_UNWIND    (SHT_LOPROC + 1) /* unwind bits */
/* Processor specific flags for the Shdr sh_flags field.  */
#define SHF_IA_64_SHORT    0x10000000  /* section near gp */
#define SHF_IA_64_NORECOV    0x20000000  /* spec insns w/o recovery */
/* Processor specific values for the Dyn d_tag field.  */
#define DT_IA_64_PLT_RESERVE    (DT_LOPROC + 0)
#define DT_IA_64_NUM    1
/* IA-64 relocations.  */
#define R_IA64_NONE    0x00    /* none */
#define R_IA64_IMM14    0x21    /* symbol + addend, add imm14 */
#define R_IA64_IMM22    0x22    /* symbol + addend, add imm22 */
#define R_IA64_IMM64    0x23    /* symbol + addend, mov imm64 */
#define R_IA64_DIR32MSB    0x24    /* symbol + addend, data4 MSB */
#define R_IA64_DIR32LSB    0x25    /* symbol + addend, data4 LSB */
#define R_IA64_DIR64MSB    0x26    /* symbol + addend, data8 MSB */
#define R_IA64_DIR64LSB    0x27    /* symbol + addend, data8 LSB */
#define R_IA64_GPREL22    0x2a    /* @gprel(sym + add), add imm22 */
#define R_IA64_GPREL64I    0x2b    /* @gprel(sym + add), mov imm64 */
#define R_IA64_GPREL32MSB    0x2c    /* @gprel(sym + add), data4 MSB */
#define R_IA64_GPREL32LSB    0x2d    /* @gprel(sym + add), data4 LSB */
#define R_IA64_GPREL64MSB    0x2e    /* @gprel(sym + add), data8 MSB */
#define R_IA64_GPREL64LSB    0x2f    /* @gprel(sym + add), data8 LSB */
#define R_IA64_LTOFF22    0x32    /* @ltoff(sym + add), add imm22 */
#define R_IA64_LTOFF64I    0x33    /* @ltoff(sym + add), mov imm64 */
#define R_IA64_PLTOFF22    0x3a    /* @pltoff(sym + add), add imm22 */
#define R_IA64_PLTOFF64I    0x3b    /* @pltoff(sym + add), mov imm64 */
#define R_IA64_PLTOFF64MSB    0x3e    /* @pltoff(sym + add), data8 MSB */
#define R_IA64_PLTOFF64LSB    0x3f    /* @pltoff(sym + add), data8 LSB */
#define R_IA64_FPTR64I    0x43    /* @fptr(sym + add), mov imm64 */
#define R_IA64_FPTR32MSB    0x44    /* @fptr(sym + add), data4 MSB */
#define R_IA64_FPTR32LSB    0x45    /* @fptr(sym + add), data4 LSB */
#define R_IA64_FPTR64MSB    0x46    /* @fptr(sym + add), data8 MSB */
#define R_IA64_FPTR64LSB    0x47    /* @fptr(sym + add), data8 LSB */
#define R_IA64_PCREL60B    0x48    /* @pcrel(sym + add), brl */
#define R_IA64_PCREL21B    0x49    /* @pcrel(sym + add), ptb, call */
#define R_IA64_PCREL21M    0x4a    /* @pcrel(sym + add), chk.s */
#define R_IA64_PCREL21F    0x4b    /* @pcrel(sym + add), fchkf */
#define R_IA64_PCREL32MSB    0x4c    /* @pcrel(sym + add), data4 MSB */
#define R_IA64_PCREL32LSB    0x4d    /* @pcrel(sym + add), data4 LSB */
#define R_IA64_PCREL64MSB    0x4e    /* @pcrel(sym + add), data8 MSB */
#define R_IA64_PCREL64LSB    0x4f    /* @pcrel(sym + add), data8 LSB */
#define R_IA64_LTOFF_FPTR22    0x52    /* @ltoff(@fptr(s+a)), imm22 */
#define R_IA64_LTOFF_FPTR64I    0x53    /* @ltoff(@fptr(s+a)), imm64 */
#define R_IA64_LTOFF_FPTR32MSB    0x54    /* @ltoff(@fptr(s+a)), data4 MSB */
#define R_IA64_LTOFF_FPTR32LSB    0x55    /* @ltoff(@fptr(s+a)), data4 LSB */
#define R_IA64_LTOFF_FPTR64MSB    0x56    /* @ltoff(@fptr(s+a)), data8 MSB */
#define R_IA64_LTOFF_FPTR64LSB    0x57    /* @ltoff(@fptr(s+a)), data8 LSB */
#define R_IA64_SEGREL32MSB    0x5c    /* @segrel(sym + add), data4 MSB */
#define R_IA64_SEGREL32LSB    0x5d    /* @segrel(sym + add), data4 LSB */
#define R_IA64_SEGREL64MSB    0x5e    /* @segrel(sym + add), data8 MSB */
#define R_IA64_SEGREL64LSB    0x5f    /* @segrel(sym + add), data8 LSB */
#define R_IA64_SECREL32MSB    0x64    /* @secrel(sym + add), data4 MSB */
#define R_IA64_SECREL32LSB    0x65    /* @secrel(sym + add), data4 LSB */
#define R_IA64_SECREL64MSB    0x66    /* @secrel(sym + add), data8 MSB */
#define R_IA64_SECREL64LSB    0x67    /* @secrel(sym + add), data8 LSB */
#define R_IA64_REL32MSB    0x6c    /* data 4 + REL */
#define R_IA64_REL32LSB    0x6d    /* data 4 + REL */
#define R_IA64_REL64MSB    0x6e    /* data 8 + REL */
#define R_IA64_REL64LSB    0x6f    /* data 8 + REL */
#define R_IA64_LTV32MSB    0x74    /* symbol + addend, data4 MSB */
#define R_IA64_LTV32LSB    0x75    /* symbol + addend, data4 LSB */
#define R_IA64_LTV64MSB    0x76    /* symbol + addend, data8 MSB */
#define R_IA64_LTV64LSB    0x77    /* symbol + addend, data8 LSB */
#define R_IA64_PCREL21BI    0x79    /* @pcrel(sym + add), 21bit inst */
#define R_IA64_PCREL22    0x7a    /* @pcrel(sym + add), 22bit inst */
#define R_IA64_PCREL64I    0x7b    /* @pcrel(sym + add), 64bit inst */
#define R_IA64_IPLTMSB    0x80    /* dynamic reloc, imported PLT, MSB */
#define R_IA64_IPLTLSB    0x81    /* dynamic reloc, imported PLT, LSB */
#define R_IA64_COPY    0x84    /* copy relocation */
#define R_IA64_SUB    0x85    /* Addend and symbol difference */
#define R_IA64_LTOFF22X    0x86    /* LTOFF22, relaxable.  */
#define R_IA64_LDXMOV    0x87    /* Use of LTOFF22X.  */
#define R_IA64_TPREL14    0x91    /* @tprel(sym + add), imm14 */
#define R_IA64_TPREL22    0x92    /* @tprel(sym + add), imm22 */
#define R_IA64_TPREL64I    0x93    /* @tprel(sym + add), imm64 */
#define R_IA64_TPREL64MSB    0x96    /* @tprel(sym + add), data8 MSB */
#define R_IA64_TPREL64LSB    0x97    /* @tprel(sym + add), data8 LSB */
#define R_IA64_LTOFF_TPREL22    0x9a    /* @ltoff(@tprel(s+a)), imm2 */
#define R_IA64_DTPMOD64MSB    0xa6    /* @dtpmod(sym + add), data8 MSB */
#define R_IA64_DTPMOD64LSB    0xa7    /* @dtpmod(sym + add), data8 LSB */
#define R_IA64_LTOFF_DTPMOD22    0xaa    /* @ltoff(@dtpmod(sym + add)), imm22 */
#define R_IA64_DTPREL14    0xb1    /* @dtprel(sym + add), imm14 */
#define R_IA64_DTPREL22    0xb2    /* @dtprel(sym + add), imm22 */
#define R_IA64_DTPREL64I    0xb3    /* @dtprel(sym + add), imm64 */
#define R_IA64_DTPREL32MSB    0xb4    /* @dtprel(sym + add), data4 MSB */
#define R_IA64_DTPREL32LSB    0xb5    /* @dtprel(sym + add), data4 LSB */
#define R_IA64_DTPREL64MSB    0xb6    /* @dtprel(sym + add), data8 MSB */
#define R_IA64_DTPREL64LSB    0xb7    /* @dtprel(sym + add), data8 LSB */
#define R_IA64_LTOFF_DTPREL22    0xba    /* @ltoff(@dtprel(s+a)), imm22 */

typedef struct elf32_rel {
  Elf32_Addr    r_offset;
  Elf32_Word    r_info;
} Elf32_Rel;
typedef struct elf64_rel {
  Elf64_Addr r_offset;    /* Location at which to apply the action */
  Elf64_Xword r_info;    /* index and type of relocation */
} Elf64_Rel;

typedef struct elf32_rela{
  Elf32_Addr    r_offset;
  Elf32_Word    r_info;
  Elf32_Sword    r_addend;
} Elf32_Rela;
typedef struct elf64_rela {
  Elf64_Addr r_offset;    /* Location at which to apply the action */
  Elf64_Xword r_info;    /* index and type of relocation */
  Elf64_Sxword r_addend;    /* Constant addend used to compute value */
} Elf64_Rela;

typedef struct elf32_sym{
  Elf32_Word    st_name;
  Elf32_Addr    st_value;
  Elf32_Word    st_size;
  unsigned char    st_info;
  unsigned char    st_other;
  Elf32_Half    st_shndx;
} Elf32_Sym;
typedef struct elf64_sym {
  Elf64_Word st_name;    /* Symbol name, index in string tbl */
  unsigned char    st_info;    /* Type and binding attributes */
  unsigned char    st_other;   /* No defined meaning, 0 */
  Elf64_Half st_shndx;    /* Associated section index */
  Elf64_Addr st_value;    /* Value of the symbol */
  Elf64_Xword st_size;    /* Associated symbol size */
} Elf64_Sym;

#define EI_NIDENT    16
typedef struct elf32_hdr{
  unsigned char    e_ident[EI_NIDENT];
  Elf32_Half    e_type;
  Elf32_Half    e_machine;
  Elf32_Word    e_version;
  Elf32_Addr    e_entry;  /* Entry point */
  Elf32_Off    e_phoff;
  Elf32_Off    e_shoff;
  Elf32_Word    e_flags;
  Elf32_Half    e_ehsize;
  Elf32_Half    e_phentsize;
  Elf32_Half    e_phnum;
  Elf32_Half    e_shentsize;
  Elf32_Half    e_shnum;
  Elf32_Half    e_shstrndx;
} Elf32_Ehdr;
typedef struct elf64_hdr {
  unsigned char    e_ident[16];    /* ELF "magic number" */
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;    /* Entry point virtual address */
  Elf64_Off e_phoff;    /* Program header table file offset */
  Elf64_Off e_shoff;    /* Section header table file offset */
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
} Elf64_Ehdr;

/* These constants define the permissions on sections in the program
   header, p_flags. */
#define PF_R    0x4
#define PF_W    0x2
#define PF_X    0x1
typedef struct elf32_phdr{
  Elf32_Word    p_type;
  Elf32_Off        p_offset;
  Elf32_Addr    p_vaddr;
  Elf32_Addr    p_paddr;
  Elf32_Word    p_filesz;
  Elf32_Word    p_memsz;
  Elf32_Word    p_flags;
  Elf32_Word    p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
  Elf64_Word p_type;
  Elf64_Word p_flags;
  Elf64_Off p_offset;    /* Segment file offset */
  Elf64_Addr p_vaddr;    /* Segment virtual address */
  Elf64_Addr p_paddr;    /* Segment physical address */
  Elf64_Xword p_filesz;    /* Segment size in file */
  Elf64_Xword p_memsz;    /* Segment size in memory */
  Elf64_Xword p_align;    /* Segment alignment, file & memory */
} Elf64_Phdr;
/* sh_type */

#define SHT_NULL    0
#define SHT_PROGBITS    1
#define SHT_SYMTAB    2
#define SHT_STRTAB    3
#define SHT_RELA    4
#define SHT_HASH    5
#define SHT_DYNAMIC    6
#define SHT_NOTE    7
#define SHT_NOBITS    8
#define SHT_REL    9
#define SHT_SHLIB    10
#define SHT_DYNSYM    11
#define SHT_NUM    12
#define SHT_LOPROC    0x70000000
#define SHT_HIPROC    0x7fffffff
#define SHT_LOUSER    0x80000000
#define SHT_HIUSER    0xffffffff
#define SHT_MIPS_LIST    0x70000000
#define SHT_MIPS_CONFLICT    0x70000002
#define SHT_MIPS_GPTAB    0x70000003
#define SHT_MIPS_UCODE    0x70000004
/* sh_flags */
#define SHF_WRITE    0x1
#define SHF_ALLOC    0x2
#define SHF_EXECINSTR    0x4
#define SHF_MASKPROC    0xf0000000
#define SHF_MIPS_GPREL    0x10000000
/* special section indexes */
#define SHN_UNDEF    0
#define SHN_LORESERVE    0xff00
#define SHN_LOPROC    0xff00
#define SHN_HIPROC    0xff1f
#define SHN_ABS    0xfff1
#define SHN_COMMON    0xfff2
#define SHN_HIRESERVE    0xffff
#define SHN_MIPS_ACCOMON    0xff00
typedef struct elf32_shdr {
  Elf32_Word    sh_name;
  Elf32_Word    sh_type;
  Elf32_Word    sh_flags;
  Elf32_Addr    sh_addr;
  Elf32_Off    sh_offset;
  Elf32_Word    sh_size;
  Elf32_Word    sh_link;
  Elf32_Word    sh_info;
  Elf32_Word    sh_addralign;
  Elf32_Word    sh_entsize;
} Elf32_Shdr;
typedef struct elf64_shdr {
  Elf64_Word sh_name;    /* Section name, index in string tbl */
  Elf64_Word sh_type;    /* Type of section */
  Elf64_Xword sh_flags;    /* Miscellaneous section attributes */
  Elf64_Addr sh_addr;    /* Section virtual addr at execution */
  Elf64_Off sh_offset;    /* Section file offset */
  Elf64_Xword sh_size;    /* Size of section in bytes */
  Elf64_Word sh_link;    /* Index of another section */
  Elf64_Word sh_info;    /* Additional section information */
  Elf64_Xword sh_addralign;    /* Section alignment */
  Elf64_Xword sh_entsize;    /* Entry size if section holds table */
} Elf64_Shdr;

#define    EI_MAG0 0   /* e_ident[] indexes */
#define    EI_MAG1 1
#define    EI_MAG2 2
#define    EI_MAG3 3
#define    EI_CLASS    4
#define    EI_DATA 5
#define    EI_VERSION  6
#define    EI_PAD  7
#define    ELFMAG0 0x7f    /* EI_MAG */
#define    ELFMAG1 'E'
#define    ELFMAG2 'L'
#define    ELFMAG3 'F'
#define    ELFMAG  "177ELF"
#define    SELFMAG 4
#define    ELFCLASSNONE    0   /* EI_CLASS */
#define    ELFCLASS32  1
#define    ELFCLASS64  2
#define    ELFCLASSNUM 3
#define ELFDATANONE    0   /* e_ident[EI_DATA] */
#define ELFDATA2LSB    1
#define ELFDATA2MSB    2
#define EV_NONE    0   /* e_version, EI_VERSION */
#define EV_CURRENT    1
#define EV_NUM    2
/* Notes used in ET_CORE */
#define NT_PRSTATUS    1
#define NT_PRFPREG    2
#define NT_PRPSINFO    3
#define NT_TASKSTRUCT    4
#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */

/* Note header in a PT_NOTE section */
typedef struct elf32_note {
  Elf32_Word    n_namesz;   /* Name size */
  Elf32_Word    n_descsz;   /* Content size */
  Elf32_Word    n_type; /* Content type */
} Elf32_Nhdr;
/* Note header in a PT_NOTE section */
typedef struct elf64_note {
  Elf64_Word n_namesz;    /* Name size */
  Elf64_Word n_descsz;    /* Content size */
  Elf64_Word n_type;    /* Content type */
} Elf64_Nhdr;

#if ELF_CLASS == ELFCLASS32
#define elfhdr    elf32_hdr
#define elf_phdr    elf32_phdr
#define elf_note    elf32_note
#define elf_shdr    elf32_shdr
#define elf_sym    elf32_sym
#define elf_addr_t    Elf32_Off
#ifdef ELF_USES_RELOCA
# define ELF_RELOC      Elf32_Rela
#else
# define ELF_RELOC      Elf32_Rel
#endif
#else
#define elfhdr    elf64_hdr
#define elf_phdr    elf64_phdr
#define elf_note    elf64_note
#define elf_shdr    elf64_shdr
#define elf_sym    elf64_sym
#define elf_addr_t    Elf64_Off
#ifdef ELF_USES_RELOCA
# define ELF_RELOC      Elf64_Rela
#else
# define ELF_RELOC      Elf64_Rel
#endif
#endif /* ELF_CLASS */
#ifndef ElfW
# if ELF_CLASS == ELFCLASS32
#  define ElfW(x)  Elf32_ ## x
#  define ELFW(x)  ELF32_ ## x
# else
#  define ElfW(x)  Elf64_ ## x
#  define ELFW(x)  ELF64_ ## x
# endif
#endif
#endif /* _QEMU_ELF_H */

头文件 fix.h 的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elf.h"

#define SHDRS 16
/*
.dynsym .dynstr .hash .rel.dyn .rel.plt
.plt .text .ARM.extab .ARM.exidx .fini_array
.init_array .dynamic .got .data
*/
#define NONE 0
#define DYNSYM 1
#define DYNSTR 2
#define HASH 3
#define RELDYN 4
#define RELPLT 5
#define PLT 6
#define TEXT 7
#define ARMEXIDX 8
#define FINIARRAY 9
#define INITARRAY 10
#define DYNAMIC 11
#define GOT 12
#define DATA 13
#define BSS 14
#define STRTAB 15
//

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章