├── .hgignore ├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── test ├── test.gdb ├── hello.c ├── hello-lib.c ├── hello-dlopen.c └── test.sh ├── LICENSE.txt ├── merge ├── grubmenu.txt ├── iself.c ├── is32bitelf.c └── merge.sh ├── utils ├── fatelf-verify.c ├── fatelf-extract.c ├── fatelf-info.c ├── fatelf-remove.c ├── fatelf-glue.c ├── fatelf-validate.c ├── fatelf-replace.c ├── fatelf-split.c ├── fatelf-utils.h └── fatelf-utils.c ├── patches ├── file-magic.diff ├── glibc.diff ├── gdb.diff ├── linux-kernel.diff └── binutils.diff ├── CMakeLists.txt ├── include └── fatelf.h ├── docs ├── building-vmware-example.txt └── fatelf-specification.txt └── README.md /.hgignore: -------------------------------------------------------------------------------- 1 | syntax:glob 2 | cmake-build 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [icculus] 2 | patreon: icculus 3 | -------------------------------------------------------------------------------- /test/test.gdb: -------------------------------------------------------------------------------- 1 | b main 2 | r 3 | bt 4 | info sharedlibrary 5 | c 6 | quit 7 | 8 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | All original code in here is public domain, and can be used for any purpose. 3 | 4 | --ryan. 5 | 6 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | int hello(void); 2 | int main(void) 3 | { 4 | /* have a buffer bigger than a page, so we can maybe find out 5 | if we put the data segment in the wrong place. */ 6 | int i; 7 | static char buffer[128 * 1024]; 8 | for (i = 0; i < sizeof (buffer); i++) 9 | buffer[i] = (char) i; 10 | 11 | return hello(); 12 | } 13 | -------------------------------------------------------------------------------- /merge/grubmenu.txt: -------------------------------------------------------------------------------- 1 | default 0 2 | color cyan/blue white/blue 3 | 4 | title Ubuntu 9.04 FatELF 32-bit, kernel 2.6.28-15-generic 5 | root (hd0,0) 6 | kernel /boot/x86/vmlinuz-2.6.28-15-generic root=/dev/sda1 ro quiet splash 7 | initrd /boot/x86/initrd.img-2.6.28-15-generic 8 | quiet 9 | 10 | title Ubuntu 9.04 FatELF 64-bit, kernel 2.6.28-15-generic 11 | root (hd0,0) 12 | kernel /boot/x86_64/vmlinuz-2.6.28-15-generic root=/dev/sda1 ro quiet splash 13 | initrd /boot/x86_64/initrd.img-2.6.28-15-generic 14 | quiet 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | Build: 7 | name: ${{ matrix.platform.name }} 8 | runs-on: ${{ matrix.platform.os }} 9 | strategy: 10 | matrix: 11 | platform: 12 | - { name: Linux, os: ubuntu-20.04, flags: -GNinja } 13 | steps: 14 | - name: Setup Linux dependencies 15 | if: runner.os == 'Linux' 16 | run: | 17 | sudo apt-get update 18 | sudo apt-get install cmake ninja-build 19 | - name: Get fatelf sources 20 | uses: actions/checkout@v2 21 | - name: Configure CMake 22 | run: cmake -B build ${{ matrix.platform.flags }} 23 | - name: Build 24 | run: cmake --build build/ 25 | -------------------------------------------------------------------------------- /test/hello-lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(__i386__) 4 | #define cpu "x86" 5 | #elif defined(__x86_64__) 6 | #define cpu "x86-64" 7 | #elif defined(__powerpc64__) 8 | #define cpu "powerpc64" 9 | #elif defined(__powerpc__) 10 | #define cpu "powerpc" 11 | #else 12 | #error Please add your CPU architecture here. 13 | #endif 14 | 15 | int hello(void) 16 | { 17 | printf("hello from a shared library! This binary's arch is: %s!\n", cpu); 18 | 19 | /* have a buffer bigger than a page, so we can maybe find out 20 | if we put the data segment in the wrong place. */ 21 | int i; 22 | static char buffer[128 * 1024]; 23 | for (i = 0; i < sizeof (buffer); i++) 24 | buffer[i] = (char) i; 25 | 26 | return 0; 27 | } 28 | 29 | /* end of hello-lib.c ... */ 30 | 31 | -------------------------------------------------------------------------------- /merge/iself.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static void check_elf(const char *fname) 8 | { 9 | static const unsigned char magic[4] = { 0x7F, 0x45, 0x4C, 0x46 }; 10 | size_t br = 0; 11 | unsigned char buf[4]; 12 | FILE *f = fopen(fname, "rb"); 13 | if (f == NULL) 14 | { 15 | fprintf(stderr, "Can't open %s: %s\n", fname, strerror(errno)); 16 | return; 17 | } 18 | 19 | br = fread(buf, 4, 1, f); 20 | fclose(f); 21 | 22 | if (br != 1) 23 | { 24 | if (ferror(f)) 25 | fprintf(stderr, "Can't read %s: %s\n", fname, strerror(errno)); 26 | return; 27 | } 28 | 29 | if (memcmp(buf, magic, 4) == 0) 30 | printf("%s\n", fname); 31 | } 32 | 33 | int main(int argc, const char **argv) 34 | { 35 | int i; 36 | for (i = 1; i < argc; i++) 37 | check_elf(argv[i]); 38 | return 0; 39 | } 40 | 41 | // end of iself.c ... 42 | 43 | 44 | -------------------------------------------------------------------------------- /test/hello-dlopen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef int (*hellofn)(void); 6 | 7 | int main(void) 8 | { 9 | int retval = 1; 10 | 11 | /* have a buffer bigger than a page, so we can maybe find out 12 | if we put the data segment in the wrong place. */ 13 | int i; 14 | static char buffer[128 * 1024]; 15 | for (i = 0; i < sizeof (buffer); i++) 16 | buffer[i] = (char) i; 17 | 18 | 19 | void *lib = dlopen("./hello.so", RTLD_NOW | RTLD_GLOBAL); 20 | if (lib == NULL) 21 | perror("dlopen"); 22 | else 23 | { 24 | hellofn phello = (hellofn) dlsym(lib, "hello"); 25 | if (phello == NULL) 26 | perror("dlsym"); 27 | else 28 | { 29 | retval = phello(); 30 | dlclose(lib); 31 | } 32 | } 33 | 34 | return retval; 35 | } 36 | 37 | /* end of hello-dlopen.c ... */ 38 | 39 | -------------------------------------------------------------------------------- /merge/is32bitelf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int check_elf(const char *fname) 8 | { 9 | static const unsigned char magic[4] = { 0x7F, 0x45, 0x4C, 0x46 }; 10 | size_t br = 0; 11 | unsigned char buf[5]; 12 | FILE *f = fopen(fname, "rb"); 13 | if (f == NULL) 14 | { 15 | fprintf(stderr, "Can't open %s: %s\n", fname, strerror(errno)); 16 | return 1; 17 | } 18 | 19 | br = fread(buf, 5, 1, f); 20 | fclose(f); 21 | 22 | if (br != 1) 23 | { 24 | if (ferror(f)) 25 | fprintf(stderr, "Can't read %s: %s\n", fname, strerror(errno)); 26 | return 1; 27 | } 28 | 29 | if (memcmp(buf, magic, 4) != 0) 30 | { 31 | fprintf(stderr, "Not an ELF file\n"); 32 | return 1; 33 | } 34 | return buf[4] == 1 ? 0 : 1; 35 | } 36 | 37 | int main(int argc, const char **argv) 38 | { 39 | return check_elf(argv[1]); 40 | } 41 | 42 | // end of iself.c ... 43 | 44 | 45 | -------------------------------------------------------------------------------- /utils/fatelf-verify.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int fatelf_verify(const char *fname, const char *target) 13 | { 14 | const int fd = xopen(fname, O_RDONLY, 0755); 15 | FATELF_header *header = xread_fatelf_header(fname, fd); 16 | const int recidx = xfind_fatelf_record(header, target); 17 | xclose(fname, fd); 18 | free(header); 19 | return (recidx < 0); 20 | } // fatelf_verify 21 | 22 | 23 | int main(int argc, const char **argv) 24 | { 25 | xfatelf_init(argc, argv); 26 | if (argc != 3) // this could stand to use getopt(), later. 27 | xfail("USAGE: %s ", argv[0]); 28 | return fatelf_verify(argv[1], argv[2]); 29 | } // main 30 | 31 | // end of fatelf-verify.c ... 32 | 33 | -------------------------------------------------------------------------------- /patches/file-magic.diff: -------------------------------------------------------------------------------- 1 | diff -rNu file-4.26-orig/magic/Magdir/fatelf file-4.26/magic/Magdir/fatelf 2 | --- file-4.26-orig/magic/Magdir/fatelf 1969-12-31 19:00:00.000000000 -0500 3 | +++ file-4.26/magic/Magdir/fatelf 2009-09-17 14:14:47.000000000 -0400 4 | @@ -0,0 +1,11 @@ 5 | + 6 | +#------------------------------------------------------------------------------ 7 | +# fatelf: file(1) magic for FatELF executables 8 | +# 9 | +# Created by: Ryan C. Gordon 10 | +0 string \372\160\16\37 FatELF 11 | +>4 leshort 0 unknown version 12 | +>4 leshort >1 unknown version 13 | +>4 leshort 1 version 1, 14 | +>>6 byte >0 %d records 15 | + 16 | diff -rNu file-4.26-orig/magic/Makefile.am file-4.26/magic/Makefile.am 17 | --- file-4.26-orig/magic/Makefile.am 2008-08-08 04:24:06.000000000 -0400 18 | +++ file-4.26/magic/Makefile.am 2009-09-17 14:15:02.000000000 -0400 19 | @@ -63,6 +63,7 @@ 20 | $(MAGIC_FRAGMENT_DIR)/epoc \ 21 | $(MAGIC_FRAGMENT_DIR)/erlang \ 22 | $(MAGIC_FRAGMENT_DIR)/esri \ 23 | +$(MAGIC_FRAGMENT_DIR)/fatelf \ 24 | $(MAGIC_FRAGMENT_DIR)/fcs \ 25 | $(MAGIC_FRAGMENT_DIR)/filesystems \ 26 | $(MAGIC_FRAGMENT_DIR)/flash \ 27 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.0) 2 | project(FatELF) 3 | 4 | execute_process( 5 | COMMAND git rev-list HEAD~.. 6 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 7 | RESULT_VARIABLE GITVERSION_RC 8 | OUTPUT_VARIABLE FATELF_VERSION 9 | ERROR_QUIET 10 | OUTPUT_STRIP_TRAILING_WHITESPACE 11 | ) 12 | 13 | 14 | if(CMAKE_COMPILER_IS_GNUCC) 15 | add_definitions(-pipe -fsigned-char -Wall -Werror) 16 | endif() 17 | 18 | add_definitions(-DAPPID=fatelf) 19 | add_definitions(-DAPPREV="${FATELF_VERSION}") 20 | 21 | include_directories(include) 22 | 23 | add_library(fatelf-utils STATIC utils/fatelf-utils.c) 24 | 25 | macro(add_fatelf_executable _NAME) 26 | add_executable(${_NAME} utils/${_NAME}.c) 27 | target_link_libraries(${_NAME} fatelf-utils) 28 | install(TARGETS ${_NAME} RUNTIME DESTINATION bin) 29 | endmacro() 30 | 31 | add_fatelf_executable(fatelf-glue) 32 | add_fatelf_executable(fatelf-info) 33 | add_fatelf_executable(fatelf-extract) 34 | add_fatelf_executable(fatelf-replace) 35 | add_fatelf_executable(fatelf-remove) 36 | add_fatelf_executable(fatelf-verify) 37 | add_fatelf_executable(fatelf-split) 38 | add_fatelf_executable(fatelf-validate) 39 | 40 | # end of CMakeLists.txt ... 41 | 42 | -------------------------------------------------------------------------------- /utils/fatelf-extract.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int fatelf_extract(const char *out, const char *fname, 13 | const char *target) 14 | { 15 | const int fd = xopen(fname, O_RDONLY, 0755); 16 | FATELF_header *header = xread_fatelf_header(fname, fd); 17 | const int recidx = xfind_fatelf_record(header, target); 18 | const int outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755); 19 | const FATELF_record *rec = &header->records[recidx]; 20 | 21 | unlink_on_xfail = out; 22 | 23 | xcopyfile_range(fname, fd, out, outfd, rec->offset, rec->size); 24 | xappend_junk(fname, fd, out, outfd, header); 25 | xclose(out, outfd); 26 | xclose(fname, fd); 27 | free(header); 28 | 29 | unlink_on_xfail = NULL; 30 | 31 | return 0; // success. 32 | } // fatelf_extract 33 | 34 | 35 | int main(int argc, const char **argv) 36 | { 37 | xfatelf_init(argc, argv); 38 | if (argc != 4) // this could stand to use getopt(), later. 39 | xfail("USAGE: %s ", argv[0]); 40 | return fatelf_extract(argv[1], argv[2], argv[3]); 41 | } // main 42 | 43 | // end of fatelf-extract.c ... 44 | 45 | -------------------------------------------------------------------------------- /include/fatelf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef __INCL_FATELF_H__ 10 | #define __INCL_FATELF_H__ 1 11 | 12 | #include 13 | 14 | /* This is little endian on disk, and looks like "FA700E1F" in a hex editor. */ 15 | #define FATELF_MAGIC (0x1F0E70FA) 16 | #define FATELF_FORMAT_VERSION (1) 17 | 18 | /* This does not count padding for page alignment at the end. */ 19 | #define FATELF_DISK_FORMAT_SIZE(bins) (8 + (24 * (bins))) 20 | 21 | /* Valid FATELF_record::word_size values... */ 22 | #define FATELF_32BITS (1) 23 | #define FATELF_64BITS (2) 24 | 25 | /* Valid FATELF_record::byte_order values... */ 26 | #define FATELF_BIGENDIAN (0) 27 | #define FATELF_LITTLEENDIAN (1) 28 | 29 | /* Values on disk are always littleendian, and align like Elf64. */ 30 | typedef struct FATELF_record 31 | { 32 | uint16_t machine; /* maps to e_machine. */ 33 | uint8_t osabi; /* maps to e_ident[EI_OSABI]. */ 34 | uint8_t osabi_version; /* maps to e_ident[EI_ABIVERSION]. */ 35 | uint8_t word_size; /* maps to e_ident[EI_CLASS]. */ 36 | uint8_t byte_order; /* maps to e_ident[EI_DATA]. */ 37 | uint8_t reserved0; 38 | uint8_t reserved1; 39 | uint64_t offset; 40 | uint64_t size; 41 | } FATELF_record; 42 | 43 | /* Values on disk are always littleendian, and align like Elf64. */ 44 | typedef struct FATELF_header 45 | { 46 | uint32_t magic; /* always FATELF_MAGIC */ 47 | uint16_t version; /* latest is always FATELF_FORMAT_VERSION */ 48 | uint8_t num_records; 49 | uint8_t reserved0; 50 | FATELF_record records[0]; /* this is actually num_records items. */ 51 | } FATELF_header; 52 | 53 | #endif 54 | 55 | /* end of fatelf.h ... */ 56 | 57 | -------------------------------------------------------------------------------- /utils/fatelf-info.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int fatelf_info(const char *fname) 13 | { 14 | const int fd = xopen(fname, O_RDONLY, 0755); 15 | FATELF_header *header = xread_fatelf_header(fname, fd); 16 | unsigned int i = 0; 17 | uint64_t junkoffset, junksize; 18 | 19 | printf("%s: FatELF format version %d\n", fname, (int) header->version); 20 | printf("%d records.\n", (int) header->num_records); 21 | 22 | if (xfind_junk(fname, fd, header, &junkoffset, &junksize)) 23 | { 24 | printf("%llu bytes of junk appended, starting at offset %llu.\n", 25 | (unsigned long long) junksize, (unsigned long long) junkoffset); 26 | } // if 27 | 28 | for (i = 0; i < header->num_records; i++) 29 | { 30 | const FATELF_record *rec = &header->records[i]; 31 | const fatelf_machine_info *machine = get_machine_by_id(rec->machine); 32 | const fatelf_osabi_info *osabi = get_osabi_by_id(rec->osabi); 33 | 34 | printf("Binary at index #%d:\n", i); 35 | printf(" OSABI %u (%s%s%s) version %u,\n", 36 | (unsigned int) rec->osabi, osabi ? osabi->name : "???", 37 | osabi ? ": " : "", osabi ? osabi->desc : "", 38 | (unsigned int) rec->osabi_version); 39 | printf(" %s bits\n", fatelf_get_wordsize_string(rec->word_size)); 40 | printf(" %s byteorder\n", fatelf_get_byteorder_name(rec->byte_order)); 41 | printf(" Machine %u (%s%s%s)\n", 42 | (unsigned int) rec->machine, machine ? machine->name : "???", 43 | machine ? ": " : "", machine ? machine->desc : ""); 44 | printf(" Offset %llu\n", (unsigned long long) rec->offset); 45 | printf(" Size %llu\n", (unsigned long long) rec->size); 46 | printf(" Target name: '%s' or 'record%u'\n", 47 | fatelf_get_target_name(rec, FATELF_WANT_EVERYTHING), i); 48 | } // for 49 | 50 | xclose(fname, fd); 51 | free(header); 52 | 53 | return 0; // success. 54 | } // fatelf_info 55 | 56 | 57 | int main(int argc, const char **argv) 58 | { 59 | xfatelf_init(argc, argv); 60 | if (argc != 2) // this could stand to use getopt(), later. 61 | xfail("USAGE: %s ", argv[0]); 62 | return fatelf_info(argv[1]); 63 | } // main 64 | 65 | // end of fatelf-info.c ... 66 | 67 | -------------------------------------------------------------------------------- /utils/fatelf-remove.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int fatelf_remove(const char *out, const char *fname, 13 | const char *target) 14 | { 15 | const int fd = xopen(fname, O_RDONLY, 0755); 16 | FATELF_header *header = xread_fatelf_header(fname, fd); 17 | const int idx = xfind_fatelf_record(header, target); 18 | const int outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755); 19 | uint64_t offset = FATELF_DISK_FORMAT_SIZE(((int)header->num_records)); 20 | int i; 21 | 22 | unlink_on_xfail = out; 23 | 24 | // pad out some bytes for the header we'll write at the end... 25 | xwrite_zeros(out, outfd, (size_t) offset); 26 | 27 | for (i = 0; i < ((int) header->num_records); i++) 28 | { 29 | if (i != idx) // not the thing we're removing? 30 | { 31 | const uint64_t binary_offset = align_to_page(offset); 32 | FATELF_record *rec = &header->records[i]; 33 | 34 | // append this binary to the final file, padded to page alignment. 35 | xwrite_zeros(out, outfd, (size_t) (binary_offset - offset)); 36 | xcopyfile_range(fname, fd, out, outfd, binary_offset, rec->size); 37 | 38 | rec->offset = binary_offset; 39 | offset = binary_offset + rec->size; 40 | } // if 41 | } // for 42 | 43 | // remove the record we chopped out. 44 | header->num_records--; 45 | if (idx < ((int) header->num_records)) 46 | { 47 | void *dst = &header->records[idx]; 48 | const void *src = &header->records[idx+1]; 49 | const size_t count = (header->num_records - idx); 50 | memmove(dst, src, sizeof (FATELF_record) * count); 51 | } // if 52 | 53 | xappend_junk(fname, fd, out, outfd, header); 54 | 55 | // Write the actual FatELF header now... 56 | xwrite_fatelf_header(out, outfd, header); 57 | 58 | xclose(out, outfd); 59 | xclose(fname, fd); 60 | free(header); 61 | 62 | unlink_on_xfail = NULL; 63 | 64 | return 0; // success. 65 | } // fatelf_remove 66 | 67 | 68 | int main(int argc, const char **argv) 69 | { 70 | xfatelf_init(argc, argv); 71 | if (argc != 4) // this could stand to use getopt(), later. 72 | xfail("USAGE: %s ", argv[0]); 73 | return fatelf_remove(argv[1], argv[2], argv[3]); 74 | } // main 75 | 76 | // end of fatelf-remove.c ... 77 | 78 | -------------------------------------------------------------------------------- /utils/fatelf-glue.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int fatelf_glue(const char *out, const char **bins, const int bincount) 13 | { 14 | int i = 0; 15 | const size_t struct_size = fatelf_header_size(bincount); 16 | FATELF_header *header = (FATELF_header *) xmalloc(struct_size); 17 | const int outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755); 18 | uint64_t offset = FATELF_DISK_FORMAT_SIZE(bincount); 19 | 20 | unlink_on_xfail = out; 21 | 22 | if (bincount == 0) 23 | xfail("Nothing to do."); 24 | else if (bincount > 0xFF) 25 | xfail("Too many binaries (max is 255)."); 26 | 27 | // pad out some bytes for the header we'll write at the end... 28 | xwrite_zeros(out, outfd, (size_t) offset); 29 | 30 | header->magic = FATELF_MAGIC; 31 | header->version = FATELF_FORMAT_VERSION; 32 | header->num_records = bincount; 33 | 34 | for (i = 0; i < bincount; i++) 35 | { 36 | int j = 0; 37 | const uint64_t binary_offset = align_to_page(offset); 38 | const char *fname = bins[i]; 39 | const int fd = xopen(fname, O_RDONLY, 0755); 40 | FATELF_record *record = &header->records[i]; 41 | 42 | xread_elf_header(fname, fd, 0, record); 43 | record->offset = binary_offset; 44 | 45 | // make sure we don't have a duplicate target. 46 | for (j = 0; j < i; j++) 47 | { 48 | if (fatelf_record_matches(record, &header->records[j])) 49 | xfail("'%s' and '%s' are for the same target.", bins[j], fname); 50 | } // for 51 | 52 | // append this binary to the final file, padded to page alignment. 53 | xwrite_zeros(out, outfd, (size_t) (binary_offset - offset)); 54 | record->size = xcopyfile(fname, fd, out, outfd); 55 | offset = binary_offset + record->size; 56 | 57 | // done with this binary! 58 | xclose(fname, fd); 59 | } // for 60 | 61 | // Write the actual FatELF header now... 62 | xwrite_fatelf_header(out, outfd, header); 63 | xclose(out, outfd); 64 | free(header); 65 | 66 | unlink_on_xfail = NULL; 67 | 68 | return 0; // success. 69 | } // fatelf_glue 70 | 71 | 72 | int main(int argc, const char **argv) 73 | { 74 | xfatelf_init(argc, argv); 75 | if (argc < 4) // this could stand to use getopt(), later. 76 | xfail("USAGE: %s [... binN]", argv[0]); 77 | return fatelf_glue(argv[1], &argv[2], argc - 2); 78 | } // main 79 | 80 | // end of fatelf-glue.c ... 81 | 82 | -------------------------------------------------------------------------------- /utils/fatelf-validate.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int fatelf_validate(const char *fname) 13 | { 14 | const int fd = xopen(fname, O_RDONLY, 0755); 15 | FATELF_header *header = xread_fatelf_header(fname, fd); 16 | int i; 17 | 18 | if (header->reserved0 != 0) 19 | xfail("FatELF header reserved field isn't zero."); 20 | 21 | for (i = 0; i < ((int)header->num_records); i++) 22 | { 23 | const FATELF_record *rec = &header->records[i]; 24 | FATELF_record elfrec; 25 | 26 | if (rec->reserved0 != 0) 27 | xfail("Reserved0 field is not zero in record #%d", i); 28 | else if (rec->reserved1 != 0) 29 | xfail("Reserved1 field is not zero in record #%d", i); 30 | else if (!get_machine_by_id(rec->machine)) 31 | xfail("Unknown machine #%d in record #%d", (int) rec->machine, i); 32 | else if (!get_osabi_by_id(rec->osabi)) 33 | xfail("Unknown OSABI #%d in record #%d", (int) rec->osabi, i); 34 | else if (!fatelf_get_byteorder_target_name(rec->byte_order)) 35 | xfail("Unknown byte order #%d in record #%d", (int) rec->byte_order, i); 36 | else if (!fatelf_get_wordsize_target_name(rec->word_size)) 37 | xfail("Unknown word size #%d in record #%d", (int) rec->word_size, i); 38 | else if (rec->offset != align_to_page(rec->offset)) 39 | xfail("Unaligned binary in record #%d", i); 40 | else if ((rec->offset + rec->size) < rec->offset) 41 | { 42 | xfail("Bogus offset+size (%llu + %llu) in record #%d", 43 | (unsigned long long) rec->offset, 44 | (unsigned long long) rec->size, i); 45 | } // else if 46 | else if ( (rec->word_size == FATELF_32BITS) && 47 | ((rec->offset + rec->size) > 0xFFFFFFFF) ) 48 | { 49 | xfail("32-bit binary past 4 gig limit in record #%d", i); 50 | } // else if 51 | 52 | // !!! FIXME: check for overlap between records? 53 | 54 | xread_elf_header(fname, fd, rec->offset, &elfrec); 55 | if (!fatelf_record_matches(rec, &elfrec)) 56 | xfail("ELF header differs from FatELF data in record #%d", i); 57 | } // for 58 | 59 | xclose(fname, fd); 60 | free(header); 61 | return 0; // success 62 | } // fatelf_validate 63 | 64 | 65 | int main(int argc, const char **argv) 66 | { 67 | xfatelf_init(argc, argv); 68 | if (argc != 2) // this could stand to use getopt(), later. 69 | xfail("USAGE: %s ", argv[0]); 70 | return fatelf_validate(argv[1]); 71 | } // main 72 | 73 | // end of fatelf-validate.c ... 74 | 75 | -------------------------------------------------------------------------------- /docs/building-vmware-example.txt: -------------------------------------------------------------------------------- 1 | 2 | Here's how to rebuild the vmware virtual machine from scratch. 3 | 4 | - Start vmware workstation. 5 | 6 | Do this twice, for amd64 and x86, in separate VMs...Name the amd64 one 7 | something like "Ubuntu 9.04 FatELF" (this is the one you'll publish) and 8 | the other something like "Ubuntux86tmp" (this is the one you'll throw away 9 | at the end). 10 | 11 | - Create new VM. 12 | - Use Ubuntu 9.04 Desktop .iso, do easy install, 13 | realname FatELF, username fatelf, password fatelf. 14 | - Log in after install, fire up a terminal. 15 | - Run update manager, get the latest and greatest. Click "Restart Later" 16 | - System -> Administration -> Login Window -> Security -> Enable Automatic Login 17 | - sudo apt-get install build-essential cmake mercurial openssh-server gcc-multilib 18 | - hg clone http://hg.icculus.org/icculus/fatelf 19 | - cd fatelf 20 | - mkdir cmake-build 21 | - cd cmake-build 22 | - cmake -DCMAKE_BUILD_TYPE=Release .. 23 | - make 24 | - sudo make install 25 | - cd 26 | - Download the fatelf version of Ubuntu .debs to the box (or feel free to spend 27 | hours patching and building things): 28 | They are available here: http://icculus.org/fatelf/vm/debs/ 29 | - sudo dpkg -i *.deb 30 | - sudo apt-get autoremove 31 | - (there's probably a better way to do this next thing.) 32 | - sudo mv /etc/apt/sources.list /etc/apt/DO_NOT_RUN_APT_UPDATES-sources.list-SERIOUSLY 33 | - Reboot to pick up new kernel. 34 | - sudo /usr/bin/vmware-config-tools.pl 35 | - (hit enter for all questions.) 36 | - cd fatelf/test 37 | - ./test.sh (see if anything fails. It shouldn't!) 38 | - sudo rm -f /boot/*-11-* /boot/memtest86+ 39 | - Shutdown and put this disk image aside for now. 40 | 41 | 42 | After both virtual machines are good to go... 43 | 44 | - Add the x86 disk to the amd64 VM, so it's /dev/sdb and the amd64 one is sda. 45 | - Boot the amd64 virtual machine from a Ubuntu install .iso, 64 or 32 bit should do. 46 | - "Try Ubuntu without any change to your computer" 47 | - Fire up a terminal. 48 | - sudo mount -t ext3 -r /dev/sda1 /mnt 49 | - cp -av /mnt/home/fatelf/fatelf . 50 | - sudo umount /mnt 51 | - cd fatelf/merge 52 | - Consider setting a vmware snapshot, here. 53 | - sudo ./merge.sh 54 | - Pray everything worked, or all this time was wasted. 55 | - Shut down the VM. 56 | - Remove the .iso ... switch back to physical CD/DVD drive. 57 | - Restart the vm, edit the grub command line to boot from the x86 disk, 58 | with root=/dev/sdb1. 59 | - Fire up a terminal. 60 | - sudo mount -t ext3 /dev/sda1 /mnt 61 | - Run sudo vmware-toolbox and shrink the virtual disk at /mnt. 62 | - sudo umount /mnt 63 | - Shut down. 64 | - Remove the x86 disk. Delete the x86 disk and VM. You're done with them. 65 | - Zip up the vmware files and start to upload. 66 | - Restart the remaining VM, make sure it worked, so you know if you have to 67 | stop the upload. Should be able to choose x86 or amd64 from the grub menu 68 | now. 69 | - Shutdown. 70 | - You're done! 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /utils/fatelf-replace.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static int xfind_fatelf_record_by_elf(const char *fname, const int fd, 13 | const char *fatfname, 14 | const FATELF_header *header) 15 | { 16 | FATELF_record record; 17 | int i; 18 | 19 | xread_elf_header(fname, fd, 0, &record); 20 | for (i = 0; i < ((int)header->num_records); i++) 21 | { 22 | if (fatelf_record_matches(&header->records[i], &record)) 23 | return i; 24 | } // for 25 | 26 | xfail("No record matches '%s' in FatELF file '%s'", fname, fatfname); 27 | return -1; 28 | } // xfind_fatelf_record_by_elf 29 | 30 | 31 | static int fatelf_replace(const char *out, const char *fname, 32 | const char *newobj) 33 | { 34 | const int fd = xopen(fname, O_RDONLY, 0755); 35 | const int newfd = xopen(newobj, O_RDONLY, 0755); 36 | FATELF_header *header = xread_fatelf_header(fname, fd); 37 | const int idx = xfind_fatelf_record_by_elf(newobj, newfd, fname, header); 38 | const int outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755); 39 | uint64_t offset = FATELF_DISK_FORMAT_SIZE(((int)header->num_records)); 40 | int i; 41 | 42 | unlink_on_xfail = out; 43 | 44 | // pad out some bytes for the header we'll write at the end... 45 | xwrite_zeros(out, outfd, (size_t) offset); 46 | 47 | for (i = 0; i < ((int) header->num_records); i++) 48 | { 49 | const uint64_t binary_offset = align_to_page(offset); 50 | FATELF_record *rec = &header->records[i]; 51 | 52 | // append this binary to the final file, padded to page alignment. 53 | xwrite_zeros(out, outfd, (size_t) (binary_offset - offset)); 54 | 55 | if (i == idx) // the thing we're replacing... 56 | rec->size = xcopyfile(newobj, newfd, out, outfd); 57 | else 58 | xcopyfile_range(fname, fd, out, outfd, binary_offset, rec->size); 59 | 60 | rec->offset = binary_offset; 61 | offset = binary_offset + rec->size; 62 | } // for 63 | 64 | xappend_junk(fname, fd, out, outfd, header); 65 | 66 | // Write the actual FatELF header now... 67 | xwrite_fatelf_header(out, outfd, header); 68 | 69 | xclose(out, outfd); 70 | xclose(newobj, newfd); 71 | xclose(fname, fd); 72 | free(header); 73 | 74 | unlink_on_xfail = NULL; 75 | 76 | return 0; // success. 77 | } // fatelf_replace 78 | 79 | 80 | int main(int argc, const char **argv) 81 | { 82 | xfatelf_init(argc, argv); 83 | if (argc != 4) // this could stand to use getopt(), later. 84 | xfail("USAGE: %s ", argv[0]); 85 | return fatelf_replace(argv[1], argv[2], argv[3]); 86 | } // main 87 | 88 | // end of fatelf-replace.c ... 89 | 90 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | AMD64=0 4 | if [ `uname -m` = "x86_64" ]; then 5 | AMD64=1 6 | echo "This is an x86_64 system." 7 | else 8 | echo "This is NOT an x86_64 system." 9 | fi 10 | 11 | set -e 12 | set -x 13 | 14 | rm -rf cmake-build 15 | mkdir cmake-build 16 | cd cmake-build 17 | cmake ../.. 18 | make -j2 19 | 20 | # Build some test programs (hello world, hello world with shared library, 21 | # hello world that uses dlopen() on shared library). 22 | gcc --std=c99 -O0 -ggdb3 -o hello.so ../hello-lib.c -shared -fPIC -m32 23 | gcc --std=c99 -O0 -ggdb3 -c -o hello-x86.o ../hello.c -m32 -Wl,-rpath,. 24 | gcc --std=c99 -O0 -ggdb3 -o hello-x86 hello-x86.o hello.so -m32 -Wl,-rpath,. 25 | gcc --std=c99 -O0 -ggdb3 -o hello-dlopen-x86 ../hello-dlopen.c -ldl -m32 26 | mv hello.so hello-x86.so 27 | 28 | gcc --std=c99 -O0 -ggdb3 -o hello.so ../hello-lib.c -shared -fPIC -m64 29 | gcc --std=c99 -O0 -ggdb3 -c -o hello-amd64.o ../hello.c -m64 -Wl,-rpath,. 30 | gcc --std=c99 -O0 -ggdb3 -o hello-amd64 hello-amd64.o hello.so -m64 -Wl,-rpath,. 31 | gcc --std=c99 -O0 -ggdb3 -o hello-dlopen-amd64 ../hello-dlopen.c -ldl -m64 32 | mv hello.so hello-amd64.so 33 | 34 | # Glue them into FatELF binaries. 35 | ./fatelf-glue hello hello-x86 hello-amd64 36 | ./fatelf-glue hello.o hello-x86.o hello-amd64.o 37 | ./fatelf-glue hello.so hello-amd64.so hello-x86.so 38 | ./fatelf-glue hello-dlopen hello-dlopen-x86 hello-dlopen-amd64 39 | 40 | # fatelf-info tests. 41 | ./fatelf-info ./hello 42 | ./fatelf-info ./hello.o 43 | ./fatelf-info ./hello.so 44 | ./fatelf-info ./hello-dlopen 45 | 46 | # fatelf-extract tests 47 | ./fatelf-extract ./extract-x86 ./hello record0 48 | diff --brief ./hello-x86 ./extract-x86 49 | ./fatelf-extract ./extract-amd64 ./hello x86_64:sysv:osabiver0:le:64bit 50 | diff --brief ./hello-amd64 ./extract-amd64 51 | 52 | # file(1) tests. 53 | file ./hello 54 | file ./hello.o 55 | file ./hello.so 56 | file ./hello-dlopen 57 | 58 | # glibc tests. 59 | ldd ./hello 60 | ldd ./hello.so 61 | ldd ./hello-dlopen 62 | 63 | # binutils tests. 64 | size ./hello 65 | size ./hello.o 66 | size ./hello.so 67 | size ./hello-dlopen 68 | nm ./hello 69 | nm ./hello.o 70 | nm ./hello.so 71 | nm ./hello-dlopen 72 | objdump -x ./hello 73 | objdump -x ./hello.o 74 | objdump -x ./hello.so 75 | objdump -x ./hello-dlopen 76 | 77 | # Test gdb. 78 | gdb -x ../test.gdb ./hello 79 | 80 | # Link directly against a FatELF object file (binutils test). 81 | gcc --std=c99 -m64 -O0 -ggdb3 -o hello-fatlink-obj-amd64 hello.o hello.so -Wl,-rpath,. 82 | gcc --std=c99 -m32 -O0 -ggdb3 -o hello-fatlink-obj-x86 hello.o hello.so -Wl,-rpath,. 83 | 84 | # Link directly against a FatELF shared library (binutils test). 85 | gcc --std=c99 -m64 -O0 -ggdb3 -o hello-fatlink-amd64 ../hello.c hello.so -Wl,-rpath,. 86 | gcc --std=c99 -m32 -O0 -ggdb3 -o hello-fatlink-x86 ../hello.c hello.so -Wl,-rpath,. 87 | 88 | # and, you know...run the programs themselves (glibc, kernel tests). 89 | ./hello 90 | ./hello-dlopen 91 | [ "x$AMD64" = "x1" ] && ./hello-fatlink-amd64 92 | [ "x$AMD64" = "x1" ] && ./hello-fatlink-obj-amd64 93 | ./hello-fatlink-x86 94 | ./hello-fatlink-obj-x86 95 | 96 | # end of test.sh ... 97 | 98 | 99 | -------------------------------------------------------------------------------- /merge/merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "x`id -u`" != "x0" ]; then 4 | echo "not root." 5 | exit 1 6 | fi 7 | 8 | set -x 9 | set -e 10 | 11 | rm -rf cmake-build 12 | mkdir -p cmake-build 13 | cd cmake-build 14 | 15 | mkdir -p /x86_64 16 | mkdir -p /x86 17 | 18 | umount /x86_64 || echo "ignore any umount errors" 19 | umount /x86 || echo "ignore any umount errors" 20 | 21 | mount -t ext3 /dev/sda1 /x86_64 22 | mount -t ext3 /dev/sdb1 /x86 23 | 24 | # Special case: it's a symlink to /lib32, so it causes an endless loop. 25 | rm -f /x86_64/lib/ld-linux.so.2 26 | ln -s ld-2.9.so /x86_64/lib/ld-linux.so.2 27 | 28 | # other issues. 29 | if [ -d /x86/lib/udev/devices ] ; then 30 | mv /x86/lib/udev/devices /x86/tmp_devices 31 | fi 32 | 33 | if [ -d /x86/usr/bin/X11 ]; then 34 | mv /x86/usr/bin/X11 /x86/tmp_X11 35 | fi 36 | 37 | # Make sure the home directory is gone. 38 | rm -rf /x86_64/home/fatelf 39 | cp -av /x86_64/etc/skel /x86_64/home/fatelf 40 | chown -R 1000 /x86_64/home/fatelf 41 | 42 | gcc -o fatelf-validate -O3 -s -I../../include -I../../utils ../../utils/fatelf-validate.c ../../utils/fatelf-utils.c 43 | gcc -o fatelf-replace -O3 -s -I../../include -I../../utils ../../utils/fatelf-replace.c ../../utils/fatelf-utils.c 44 | gcc -o fatelf-glue -O3 -s -I../../include -I../../utils ../../utils/fatelf-glue.c ../../utils/fatelf-utils.c 45 | gcc -o iself -s -O3 ../iself.c 46 | gcc -o is32bitelf -s -O3 ../is32bitelf.c 47 | 48 | if [ ! -f ./binaries-32 ]; then 49 | time for feh in bin boot etc lib opt sbin usr/bin usr/games usr/sbin usr/X11R6 usr/lib usr/local var/lib ; do find /x86/$feh -follow -type f -exec ./iself {} \; ; done |perl -w -pi -e 's/\A\/x86\///;' |sort |uniq > ./binaries-32 50 | fi 51 | 52 | for feh in `cat binaries-32` ; do 53 | mkdir -p --mode=0755 `dirname "/x86_64/$feh"` 54 | if [ ! -f "/x86_64/$feh" ]; then 55 | cp -a "/x86/$feh" "/x86_64/$feh" 56 | else 57 | ISFATELF=0 58 | ./fatelf-validate "/x86_64/$feh" && ISFATELF=1 59 | if [ "x$ISFATELF" = "x1" ]; then 60 | ./fatelf-replace tmp-fatelf "/x86_64/$feh" "/x86/$feh" 61 | chmod --reference="/x86_64/$feh" tmp-fatelf 62 | mv tmp-fatelf "/x86_64/$feh" 63 | else 64 | SRCIS32BIT=0 65 | DSTIS32BIT=0 66 | ./is32bitelf "/x86/$feh" && SRCIS32BIT=1 67 | ./is32bitelf "/x86_64/$feh" && DSTIS32BIT=1 68 | if [ "x$SRCIS32BIT" != "x$DSTIS32BIT" ]; then 69 | ./fatelf-glue tmp-fatelf "/x86_64/$feh" "/x86/$feh" 70 | chmod --reference="/x86_64/$feh" tmp-fatelf 71 | mv tmp-fatelf "/x86_64/$feh" 72 | fi 73 | fi 74 | fi 75 | done 76 | 77 | # We don't need /lib32 and /lib64, but symlink them to /lib just in case. 78 | rm -rf /x86_64/lib32 79 | rm -rf /x86_64/lib64 80 | ln -s /lib /x86_64/lib32 81 | ln -s /lib /x86_64/lib64 82 | 83 | # Set up the boot bits. 84 | mkdir -p /x86_64/boot/x86_64 85 | mkdir -p /x86_64/boot/x86 86 | mv /x86_64/boot/*-generic /x86_64/boot/x86_64/ 87 | cp -av /x86/boot/*-generic /x86_64/boot/x86/ 88 | cp ../grubmenu.txt /x86_64/boot/grub/menu.lst 89 | 90 | # Set the hostname. 91 | echo "fatelf" > /x86_64/etc/hostname 92 | 93 | # Hack: force hald to regenerate cache on each run, since it writes a size_t 94 | # in there that causes crashes when you switch between 64 and 32 bit mode. 95 | echo "rm -f /var/cache/hald/fdi-cache" >> /x86_64/etc/default/hal 96 | 97 | # Put some things back. 98 | mv /x86/tmp_devices /x86/lib/udev/devices 99 | mv /x86/tmp_X11 /x86/usr/bin/X11 100 | 101 | umount /x86 102 | umount /x86_64 103 | 104 | # We disable fsck intervals...this is a demo, after all! 105 | set +e 106 | time fsck.ext3 -D -C 0 -f /dev/sda1 107 | tune2fs -c 0 /dev/sda1 108 | tune2fs -i 0 /dev/sda1 109 | 110 | # end of merge.sh ... 111 | 112 | -------------------------------------------------------------------------------- /docs/fatelf-specification.txt: -------------------------------------------------------------------------------- 1 | FatELF specification, version 1. 2 | 3 | This specification is written in plain English, which is less efficient than 4 | just listing a handful of C structs. If you just want the structs, those are 5 | in include/fatelf.h. This file is here to hopefully clarify those data 6 | structures, and also allow for a complete clean-room implementation. 7 | 8 | FatELF is a simple container format for storing multiple Executable and 9 | Linkable Format (ELF) binaries in a single file. The file format is as follows. 10 | 11 | All fields are little endian on all platforms, and align like Elf64. However, 12 | the ELF binaries stored in the container format follow the usual rules of the 13 | ELF format for their target platform. 14 | 15 | FatELF Header: 16 | 17 | All FatELF files start with a "magic" number that identifies it as a FatELF 18 | binary. If this magic number is not present, the file in question is not in 19 | FatELF format. 20 | 21 | The magic number is four bytes, and when read as a 32-bit little endian value 22 | is 0x1F0E70FA. If read as four unsigned bytes, their hexadecimal value is: 23 | 24 | FA 70 0E 1F 25 | 26 | If the magic value is present, the file is FatELF. Otherwise, the reader 27 | should treat the file as a regular ELF file (or, perhaps failing that, invalid 28 | data). 29 | 30 | Following the magic value is an unsigned, 16-bit value, representing the 31 | version of the FatELF structure. The magic value and this version value are 32 | always guaranteed to be the first data in a FatELF file, but any other 33 | structure can change. As such, FatELF files with unrecognized versions should 34 | be rejected by the reader as invalid. 35 | 36 | At this time, the only valid version is 1. Future revisions of this spec may 37 | add new version values. In such a case, implementors are encouraged to handle 38 | legacy versions if possible. 39 | 40 | 41 | 42 | VERSION 1 FORMAT. 43 | 44 | Following the version value is an unsigned byte that contains the number of 45 | records in this file. Each ELF binary contained within the file supplies a 46 | separate record. We will call this value the "record count." 47 | 48 | The next byte is reserved at this time, and is positioned for the sake of 49 | alignment. It must be set to zero. 50 | 51 | Thereafter, we have a series of records equal to the number reported in the 52 | record count, laid out in sequence. 53 | 54 | The record format is as follows. 55 | 56 | Each record starts with an unsigned, 16-bit value that represents the machine 57 | architecture for this record. This field maps to e_machine in the ELF header. 58 | Next come four unsigned, 8-bit values. These represent, in order, the OSABI, 59 | OSABI version, word size and byte order of the referenced ELF binary. These 60 | fields map to e_ident[EI_OSABI], e_ident[EI_ABIVERSION], e_ident[EI_CLASS] and 61 | e_ident[EI_DATA] in the ELF header. Please note that the FatELF structures 62 | themselves are always little endian and aligned to Elf64 standards, no matter 63 | what these fields contain. 64 | 65 | The next two bytes are reserved at this time, and are positioned for the sake of 66 | alignment. They must be set to zero. 67 | 68 | The next two fields of the record are unsigned, 64-bit integers that represent 69 | the offset and size of the contained ELF binary. The offset is in bytes and 70 | starts from the beginning of the file. It is illegal for the offset to not 71 | align to the requirements of the specific architecture. For example, if you 72 | have a platform that aligns memory pages on 4096 byte boundaries, then that 73 | platform's ELF binary would have to start at offset 4096, 8192, etc. A 74 | different binary in the same file may have to align different. The FatELF file 75 | should pad the files with null chars where appropriate to supply the proper 76 | alignment. This allows any given ELF binary to be memory-mapped by the system. 77 | 78 | It is illegal to have two identical records, that is, two records that only 79 | differ by offset and size. In such a case, behaviour is undefined: 80 | implementors are free to choose whichever record they please. 81 | 82 | It is illegal to have two records overlap; a record's offset and size may not 83 | share any bytes with another ELF binary in the file. 84 | 85 | Following the list of records are the actual ELF binaries. FatELF makes no 86 | promises about the data, format or layout here, except to say that any given 87 | ELF binary will be aligned in the file to match the platform's requirements, 88 | so that even in a container with other binaries that have different alignment 89 | requirements, the system can still properly memory-map the desired binary. 90 | 91 | It is important that the reader not trust the FatELF information and still 92 | properly parse the real ELF headers of a given binary. If they do not match 93 | what is expected, the implementation should reject the file outright as 94 | corrupted or malicious. 95 | 96 | -------------------------------------------------------------------------------- /utils/fatelf-split.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #define FATELF_UTILS 1 10 | #include "fatelf-utils.h" 11 | 12 | static char *make_filename(const char *base, const int wants, 13 | const FATELF_record *rec) 14 | { 15 | const char *target = fatelf_get_target_name(rec, wants); 16 | const size_t len = strlen(base) + strlen(target) + 2; 17 | char *retval = (char *) xmalloc(len); 18 | snprintf(retval, len, "%s-%s", base, target); 19 | return retval; 20 | } // make_filename 21 | 22 | 23 | static inline int unsorted(const FATELF_record *a, const FATELF_record *b) 24 | { 25 | #define TEST_UNSORTED(field) \ 26 | if (a->field > b->field) \ 27 | return 1; \ 28 | else if (a->field < b->field) \ 29 | return 0; 30 | 31 | // This is the in order of precedence of fields. 32 | TEST_UNSORTED(machine); 33 | TEST_UNSORTED(word_size); 34 | TEST_UNSORTED(byte_order); 35 | TEST_UNSORTED(osabi); 36 | TEST_UNSORTED(osabi_version); 37 | 38 | #undef TEST_UNSORTED 39 | 40 | return 0; 41 | } // unsorted 42 | 43 | 44 | static int fatelf_split(const char *fname) 45 | { 46 | const int fd = xopen(fname, O_RDONLY, 0755); 47 | FATELF_header *header = xread_fatelf_header(fname, fd); 48 | const size_t len = sizeof (FATELF_record *) * header->num_records; 49 | FATELF_record **sorted = (FATELF_record **) xmalloc(len); 50 | const int maxrecs = header->num_records; 51 | int is_sorted = 1; 52 | int i = 0; 53 | 54 | // Try to keep the filenames as short as possible. To start, sort 55 | // the records so we know which items are relevant. 56 | for (i = 0; i < ((int) header->num_records); i++) 57 | sorted[i] = &header->records[i]; 58 | 59 | do // bubble sort ftw. 60 | { 61 | is_sorted = 1; 62 | for (i = 0; i < ((int)header->num_records)-1; i++) 63 | { 64 | if (unsorted(sorted[i], sorted[i+1])) 65 | { 66 | FATELF_record *tmp = sorted[i]; 67 | sorted[i] = sorted[i+1]; 68 | sorted[i+1] = tmp; 69 | is_sorted = 0; 70 | } // if 71 | } // for 72 | } while (!is_sorted); 73 | 74 | // now dump each ELF file, naming it with just the minimum set of 75 | // attributes that make it unique. We do this by checking the item 76 | // sorted before it and after it to see what matches. 77 | 78 | // This isn't perfect...you might get a list like this case... 79 | // 80 | // mybin-i386 81 | // mybin-ppc:32bits:be 82 | // mybin-ppc:32bits:le 83 | // mybin-ppc64 84 | // mybin-x86_64 85 | // 86 | // ...where those "32bits:" parts are superfluous. 87 | 88 | for (i = 0; i < maxrecs; i++) 89 | { 90 | const FATELF_record *rec = sorted[i]; 91 | const FATELF_record *prev = (i > 0) ? sorted[i-1] : NULL; 92 | const FATELF_record *next = (i < maxrecs-1) ? sorted[i+1] : NULL; 93 | char *out = NULL; 94 | int outfd = -1; 95 | int wants = 0; 96 | int unique = 0; 97 | 98 | #define TEST_WANT(field, flag) \ 99 | if (!unique) { \ 100 | wants |= FATELF_WANT_##flag; \ 101 | if ((prev) && (prev->field != rec->field)) prev = NULL; \ 102 | if ((next) && (next->field != rec->field)) next = NULL; \ 103 | if (!prev && !next) unique = 1; \ 104 | } 105 | 106 | // This must be in the same order as the TEST_UNSORTED things above. 107 | TEST_WANT(machine, MACHINE); 108 | TEST_WANT(word_size, WORDSIZE); 109 | TEST_WANT(byte_order, BYTEORDER); 110 | TEST_WANT(osabi, OSABI); 111 | TEST_WANT(osabi_version, OSABIVER); 112 | 113 | #undef TEST_WANT 114 | 115 | out = make_filename(fname, wants, rec); 116 | outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755); 117 | unlink_on_xfail = out; 118 | xcopyfile_range(fname, fd, out, outfd, rec->offset, rec->size); 119 | xappend_junk(fname, fd, out, outfd, header); 120 | xclose(out, outfd); 121 | unlink_on_xfail = NULL; 122 | free(out); 123 | } // for 124 | 125 | free(sorted); 126 | xclose(fname, fd); 127 | free(header); 128 | 129 | return 0; // success. 130 | } // fatelf_split 131 | 132 | 133 | int main(int argc, const char **argv) 134 | { 135 | xfatelf_init(argc, argv); 136 | if (argc != 2) // this could stand to use getopt(), later. 137 | xfail("USAGE: %s ", argv[0]); 138 | return fatelf_split(argv[1]); 139 | } // main 140 | 141 | // end of fatelf-split.c ... 142 | 143 | -------------------------------------------------------------------------------- /utils/fatelf-utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | /* code shared between all FatELF utilities... */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "fatelf.h" 20 | 21 | #if !FATELF_UTILS 22 | #error Do not include this file outside of FatELF. 23 | #endif 24 | 25 | #ifdef __GNUC__ 26 | #define FATELF_ISPRINTF(x,y) __attribute__((format (printf, x, y))) 27 | #else 28 | #define FATELF_ISPRINTF(x,y) 29 | #endif 30 | 31 | extern const char *unlink_on_xfail; 32 | extern const char *fatelf_build_version; 33 | 34 | #define FATELF_WANT_MACHINE (1 << 0) 35 | #define FATELF_WANT_OSABI (1 << 1) 36 | #define FATELF_WANT_OSABIVER (1 << 2) 37 | #define FATELF_WANT_WORDSIZE (1 << 3) 38 | #define FATELF_WANT_BYTEORDER (1 << 4) 39 | #define FATELF_WANT_EVERYTHING 0xFFFF 40 | 41 | typedef struct fatelf_machine_info 42 | { 43 | uint16_t id; 44 | const char *name; 45 | const char *desc; 46 | } fatelf_machine_info; 47 | 48 | 49 | typedef struct fatelf_osabi_info 50 | { 51 | uint8_t id; 52 | const char *name; 53 | const char *desc; 54 | } fatelf_osabi_info; 55 | 56 | 57 | // all functions that start with 'x' may call exit() on error! 58 | 59 | // Report an error to stderr and terminate immediately with exit(1). 60 | void xfail(const char *fmt, ...) FATELF_ISPRINTF(1,2); 61 | 62 | // Wrap malloc() with an xfail(), so this returns memory or calls exit(). 63 | // Memory is guaranteed to be initialized to zero. 64 | void *xmalloc(const size_t len); 65 | 66 | // Allocate a copy of (str), xfail() on allocation failure. 67 | char *xstrdup(const char *str); 68 | 69 | // These all xfail() on error and handle EINTR for you. 70 | int xopen(const char *fname, const int flags, const int perms); 71 | ssize_t xread(const char *fname, const int fd, void *buf, 72 | const size_t len, const int must_read); 73 | ssize_t xwrite(const char *fname, const int fd, 74 | const void *buf, const size_t len); 75 | void xclose(const char *fname, const int fd); 76 | void xlseek(const char *fname, const int fd, const off_t o, const int whence); 77 | 78 | // This writes len null bytes to (fd). 79 | void xwrite_zeros(const char *fname, const int fd, size_t len); 80 | 81 | // copy file from infd to current seek position in outfd, until infd's EOF. 82 | uint64_t xcopyfile(const char *in, const int infd, 83 | const char *out, const int outfd); 84 | 85 | // copy file from infd to current offset in outfd, for size bytes. 86 | void xcopyfile_range(const char *in, const int infd, 87 | const char *out, const int outfd, 88 | const uint64_t offset, const uint64_t size); 89 | 90 | // get the length of an open file in bytes. 91 | uint64_t xget_file_size(const char *fname, const int fd); 92 | 93 | // read the parts of an ELF header we care about. 94 | void xread_elf_header(const char *fname, const int fd, const uint64_t offset, 95 | FATELF_record *rec); 96 | 97 | // How many bytes to allocate for a FATELF_header. 98 | size_t fatelf_header_size(const int bincount); 99 | 100 | // Put FatELF header to disk. Will seek to 0 first. 101 | void xwrite_fatelf_header(const char *fname, const int fd, 102 | const FATELF_header *header); 103 | 104 | // Get FatELF header from disk. Will seek to 0 first. 105 | // don't forget to free() the returned pointer! 106 | FATELF_header *xread_fatelf_header(const char *fname, const int fd); 107 | 108 | // Locate non-FatELF data at the end of a FatELF file fd, based on 109 | // header header. Returns non-zero if junk found, and fills in offset and 110 | // size. 111 | int xfind_junk(const char *fname, const int fd, const FATELF_header *header, 112 | uint64_t *offset, uint64_t *size); 113 | 114 | // Write non-FatELF data at the end of FatELF file fd to current position in 115 | // outfd, based on header header. 116 | void xappend_junk(const char *fname, const int fd, 117 | const char *out, const int outfd, 118 | const FATELF_header *header); 119 | 120 | // Align a value to the page size. 121 | uint64_t align_to_page(const uint64_t offset); 122 | 123 | // find the record closest to the end of the file. -1 on error! 124 | int find_furthest_record(const FATELF_header *header); 125 | 126 | const fatelf_machine_info *get_machine_by_id(const uint16_t id); 127 | const fatelf_machine_info *get_machine_by_name(const char *name); 128 | const fatelf_osabi_info *get_osabi_by_id(const uint8_t id); 129 | const fatelf_osabi_info *get_osabi_by_name(const char *name); 130 | 131 | // Returns a string that can be used to target a specific record. 132 | const char *fatelf_get_target_name(const FATELF_record *rec, const int wants); 133 | 134 | // these return static strings of english words. 135 | const char *fatelf_get_wordsize_string(const uint8_t wordsize); 136 | const char *fatelf_get_byteorder_name(const uint8_t byteorder); 137 | const char *fatelf_get_byteorder_target_name(const uint8_t byteorder); 138 | const char *fatelf_get_wordsize_target_name(const uint8_t wordsize); 139 | 140 | // Find the desired record in the FatELF header, based on a string in 141 | // various formats. 142 | int xfind_fatelf_record(const FATELF_header *header, const char *target); 143 | 144 | // non-zero if all pertinent fields in a match b. 145 | int fatelf_record_matches(const FATELF_record *a, const FATELF_record *b); 146 | 147 | // Call this at the start of main(). 148 | void xfatelf_init(int argc, const char **argv); 149 | 150 | // end of fatelf-utils.h ... 151 | 152 | -------------------------------------------------------------------------------- /patches/glibc.diff: -------------------------------------------------------------------------------- 1 | diff -ruBb glibc-2.19-orig/elf/dl-load.c glibc-2.19/elf/dl-load.c 2 | --- glibc-2.19-orig/elf/dl-load.c 2015-02-28 06:52:37.000000000 -0800 3 | +++ glibc-2.19/elf/dl-load.c 2015-02-28 06:51:36.442857109 -0800 4 | @@ -26,6 +26,7 @@ 5 | #include 6 | #include 7 | #include 8 | +#include 9 | #include 10 | #include 11 | #include 12 | @@ -131,6 +132,7 @@ 13 | # define FILEBUF_SIZE 832 14 | #endif 15 | char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); 16 | + ElfW(Off) base_offset; /* for FatELF binaries. */ 17 | }; 18 | 19 | /* This is the decomposed LD_LIBRARY_PATH search path. */ 20 | @@ -1078,7 +1080,7 @@ 21 | else 22 | { 23 | phdr = alloca (maplength); 24 | - __lseek (fd, header->e_phoff, SEEK_SET); 25 | + __lseek (fd, header->e_phoff + fbp->base_offset, SEEK_SET); 26 | if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) 27 | { 28 | errstring = N_("cannot read file data"); 29 | @@ -1293,7 +1295,7 @@ 30 | l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength, 31 | c->prot, 32 | MAP_COPY|MAP_FILE, 33 | - fd, c->mapoff); 34 | + fd, c->mapoff + fbp->base_offset); 35 | if (__builtin_expect ((void *) l->l_map_start == MAP_FAILED, 0)) 36 | { 37 | map_error: 38 | @@ -1344,7 +1346,7 @@ 39 | && (__mmap ((void *) (l->l_addr + c->mapstart), 40 | c->mapend - c->mapstart, c->prot, 41 | MAP_FIXED|MAP_COPY|MAP_FILE, 42 | - fd, c->mapoff) 43 | + fd, c->mapoff + fbp->base_offset) 44 | == MAP_FAILED)) 45 | goto map_error; 46 | 47 | @@ -1862,6 +1864,85 @@ 48 | } 49 | 50 | 51 | +#define ELF32_CLASS ELFCLASS32 52 | +#define ELF64_CLASS ELFCLASS64 53 | +#ifndef VALID_ELF_HEADER 54 | +# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0) 55 | +# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV) 56 | +# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0) 57 | +#endif 58 | +#if BYTE_ORDER == BIG_ENDIAN 59 | +#define le16_to_cpu(x) __bswap_16(x) 60 | +#define le32_to_cpu(x) __bswap_32(x) 61 | +#define le64_to_cpu(x) __bswap_64(x) 62 | +#else 63 | +#define le16_to_cpu(x) (x) 64 | +#define le32_to_cpu(x) (x) 65 | +#define le64_to_cpu(x) (x) 66 | +#endif 67 | +/* See if (fd) is a handle to a FatELF file. If so, seek to the start of 68 | + the ELF binary we want. Returns an error string, or NULL on success. 69 | + If this file isn't FatELF, we consider that a success condition. */ 70 | +static const char * 71 | +examine_fatelf(const int fd, struct filebuf *fbp) 72 | +{ 73 | + const fatelf_header *header = (fatelf_header *) fbp->buf; 74 | + size_t records = (fbp->len - sizeof (fatelf_header)) / sizeof (fatelf_record); 75 | + ElfW(Ehdr) ehdr; 76 | + size_t i; 77 | + 78 | + fbp->base_offset = 0; /* make sure this is sane. */ 79 | + 80 | + if (fbp->len < sizeof (fatelf_header)) 81 | + return NULL; /* Not FatELF (probably not ELF either, but oh well.) */ 82 | + else if (le32_to_cpu(header->magic) != FATELF_MAGIC) 83 | + return NULL; /* not FatELF; go on with normal ELF handling code. */ 84 | + else if (le16_to_cpu(header->version) != FATELF_FORMAT_VERSION) 85 | + return N_("unrecognized FatELF format version"); 86 | + 87 | + /* XXX There may be up to 255 records, but usually there will be 2 to 5. 88 | + If this proves to be a problem, we can make the effort to load more data 89 | + from fd here. But right now, we fit between 21 and 34 records here! */ 90 | + if (header->num_records < records) 91 | + records = (size_t) header->num_records; 92 | + 93 | + memset((void *) &ehdr, '\0', sizeof (ehdr)); 94 | + 95 | + for (i = 0; i < records; i++) 96 | + { 97 | + const fatelf_record *record = &header->records[i]; 98 | + const uint64_t offset = le64_to_cpu(record->offset); 99 | + const uint64_t size = le64_to_cpu(record->size); 100 | + const uint64_t end_offset = offset + size; 101 | + 102 | + /* the only fields any of the elf_machine_matches_host()s care about. */ 103 | + ehdr.e_machine = (ElfW(Half)) le16_to_cpu(record->machine); 104 | + ehdr.e_ident[EI_OSABI] = record->osabi; 105 | + ehdr.e_ident[EI_ABIVERSION] = record->osabi_version; 106 | + ehdr.e_ident[EI_CLASS] = record->word_size; 107 | + ehdr.e_ident[EI_DATA] = record->byte_order; 108 | + 109 | + /* if we fail a test here, we just jump to the next record. */ 110 | + if (!VALID_ELF_OSABI(record->osabi)) 111 | + continue; 112 | + else if (!VALID_ELF_ABIVERSION(record->osabi, record->osabi_version)) 113 | + continue; 114 | + else if (!elf_machine_matches_host(&ehdr)) 115 | + continue; 116 | + else if (((ElfW(Off)) end_offset) < offset) /* overflow? */ 117 | + continue; 118 | + else if (__lseek(fd, (off_t)le64_to_cpu(record->offset), SEEK_SET) == -1) 119 | + continue; 120 | + 121 | + /* reset fbp with the actual ELF data... */ 122 | + fbp->base_offset = (ElfW(Off)) offset; 123 | + fbp->len = __libc_read(fd, fbp->buf, sizeof (fbp->buf)); 124 | + return NULL; /* no error! */ 125 | + } 126 | + 127 | + return N_("No compatible ELF binaries in this FatELF file"); 128 | +} 129 | + 130 | /* Open a file and verify it is an ELF file for this architecture. We 131 | ignore only ELF files for other architectures. Non-ELF files and 132 | ELF files with different header information cause fatal errors since 133 | @@ -1952,6 +2033,10 @@ 134 | } 135 | while (__builtin_expect (fbp->len < sizeof (ElfW(Ehdr)), 0)); 136 | 137 | + errstring = examine_fatelf(fd, fbp); 138 | + if (errstring) 139 | + goto call_lose; 140 | + 141 | /* This is where the ELF header is loaded. */ 142 | ehdr = (ElfW(Ehdr) *) fbp->buf; 143 | 144 | @@ -2073,7 +2158,7 @@ 145 | else 146 | { 147 | phdr = alloca (maplength); 148 | - __lseek (fd, ehdr->e_phoff, SEEK_SET); 149 | + __lseek (fd, ehdr->e_phoff + fbp->base_offset, SEEK_SET); 150 | if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) 151 | { 152 | read_error: 153 | @@ -2095,7 +2180,7 @@ 154 | else 155 | { 156 | abi_note = alloca (size); 157 | - __lseek (fd, ph->p_offset, SEEK_SET); 158 | + __lseek (fd, ph->p_offset + fbp->base_offset, SEEK_SET); 159 | if (__libc_read (fd, (void *) abi_note, size) != size) 160 | goto read_error; 161 | } 162 | diff -ruBb glibc-2.19-orig/elf/elf.h glibc-2.19/elf/elf.h 163 | --- glibc-2.19-orig/elf/elf.h 2015-02-28 06:52:37.000000000 -0800 164 | +++ glibc-2.19/elf/elf.h 2015-02-28 06:49:49.410853919 -0800 165 | @@ -59,6 +59,34 @@ 166 | typedef Elf32_Half Elf32_Versym; 167 | typedef Elf64_Half Elf64_Versym; 168 | 169 | +/* This is little endian on disk, and looks like "FA700E1F" in a hex editor. */ 170 | +#define FATELF_MAGIC (0x1F0E70FA) 171 | +#define FATELF_FORMAT_VERSION (1) 172 | + 173 | +/* FatELF values on disk are always littleendian, and align like Elf64. */ 174 | +typedef struct 175 | +{ 176 | + uint16_t machine; /* maps to e_machine */ 177 | + uint8_t osabi; /* maps to e_ident[EI_OSABI] */ 178 | + uint8_t osabi_version; /* maps to e_ident[EI_ABIVERSION] */ 179 | + uint8_t word_size; /* maps to e_ident[EI_CLASS] */ 180 | + uint8_t byte_order; /* maps to e_ident[EI_DATA] */ 181 | + uint8_t reserved0; 182 | + uint8_t reserved1; 183 | + uint64_t offset; 184 | + uint64_t size; 185 | +} fatelf_record; 186 | + 187 | +/* FatELF values on disk are always littleendian, and align like Elf64. */ 188 | +typedef struct 189 | +{ 190 | + uint32_t magic; /* always FATELF_MAGIC */ 191 | + uint16_t version; /* latest is always FATELF_FORMAT_VERSION */ 192 | + uint8_t num_records; 193 | + uint8_t reserved0; 194 | + fatelf_record records[]; 195 | +} fatelf_header; 196 | + 197 | 198 | /* The ELF file header. This appears at the start of every ELF file. */ 199 | 200 | -------------------------------------------------------------------------------- /patches/gdb.diff: -------------------------------------------------------------------------------- 1 | diff -ruBb gdb-7.8-orig/bfd/bfd.c gdb-7.8/bfd/bfd.c 2 | --- gdb-7.8-orig/bfd/bfd.c 2014-07-29 05:37:42.000000000 -0700 3 | +++ gdb-7.8/bfd/bfd.c 2015-02-27 23:33:08.210073035 -0800 4 | @@ -309,6 +309,10 @@ 5 | . {* Set if only required symbols should be added in the link hash table for 6 | . this object. Used by VMS linkers. *} 7 | . unsigned int selective_search : 1; 8 | +. 9 | +. {* Base offset, in bytes, of object inside a container file, such as FatELF, 10 | +. or a Mach-O Universal Binary. This will be zero for most things. *} 11 | +. ufile_ptr base_offset; 12 | .}; 13 | . 14 | .{* See note beside bfd_set_section_userdata. *} 15 | diff -ruBb gdb-7.8-orig/bfd/bfd-in2.h gdb-7.8/bfd/bfd-in2.h 16 | --- gdb-7.8-orig/bfd/bfd-in2.h 2014-07-29 05:37:42.000000000 -0700 17 | +++ gdb-7.8/bfd/bfd-in2.h 2015-02-27 23:33:56.670074479 -0800 18 | @@ -6484,6 +6484,10 @@ 19 | /* Set if only required symbols should be added in the link hash table for 20 | this object. Used by VMS linkers. */ 21 | unsigned int selective_search : 1; 22 | + 23 | + /* Base offset, in bytes, of object inside a container file, such as FatELF, 24 | + or a Mach-O Universal Binary. This will be zero for most things. */ 25 | + ufile_ptr base_offset; 26 | }; 27 | 28 | /* See note beside bfd_set_section_userdata. */ 29 | diff -ruBb gdb-7.8-orig/bfd/bfdio.c gdb-7.8/bfd/bfdio.c 30 | --- gdb-7.8-orig/bfd/bfdio.c 2014-06-11 09:34:40.000000000 -0700 31 | +++ gdb-7.8/bfd/bfdio.c 2015-02-27 23:35:20.190076968 -0800 32 | @@ -314,6 +314,7 @@ 33 | { 34 | bfd *parent_bfd = abfd; 35 | 36 | + file_position += abfd->base_offset; 37 | while (parent_bfd->my_archive != NULL) 38 | { 39 | file_position += parent_bfd->origin; 40 | @@ -347,7 +348,7 @@ 41 | { 42 | /* Adjust `where' field. */ 43 | if (direction == SEEK_SET) 44 | - abfd->where = position; 45 | + abfd->where = position + abfd->base_offset; 46 | else 47 | abfd->where += position; 48 | } 49 | diff -ruBb gdb-7.8-orig/bfd/elfcode.h gdb-7.8/bfd/elfcode.h 50 | --- gdb-7.8-orig/bfd/elfcode.h 2015-02-27 23:31:58.000000000 -0800 51 | +++ gdb-7.8/bfd/elfcode.h 2015-02-27 23:37:34.262080964 -0800 52 | @@ -497,6 +496,12 @@ 53 | asection *s; 54 | bfd_size_type amt; 55 | const bfd_target *target; 56 | + const FatElf_External_Hdr *x_fathdr = (FatElf_External_Hdr *) &x_ehdr; 57 | + bfd_vma base_offset = 0; 58 | + 59 | + ebd = get_elf_backend_data (abfd); 60 | + if (ebd->s->arch_size != ARCH_SIZE) 61 | + goto got_wrong_format_error; 62 | 63 | /* Read in the ELF header in external format. */ 64 | 65 | @@ -508,6 +513,102 @@ 66 | goto got_no_match; 67 | } 68 | 69 | + /* See if this is a FatELF file, and if so, locate the correct record. */ 70 | + if (bfd_getl32(&x_fathdr->magic) == FATELF_MAGIC) 71 | + { 72 | + FatElf_External_Record *x_fatrec_ptr; 73 | + unsigned char fatindex; 74 | + file_ptr seekpos = -((file_ptr) sizeof (x_ehdr)); 75 | + 76 | + if (bfd_getl16(&x_fathdr->version) != FATELF_FORMAT_VERSION) 77 | + goto got_wrong_format_error; 78 | + 79 | + /* reposition at the end of the FatELF header for record reading... */ 80 | + seekpos += ((file_ptr) sizeof (*x_fathdr)); 81 | + if (bfd_seek (abfd, seekpos, SEEK_CUR) != 0) 82 | + goto got_no_match; 83 | + 84 | + amt = sizeof (*x_fatrec_ptr) * x_fathdr->num_records; 85 | + x_fatrec_ptr = (FatElf_External_Record *) bfd_alloc (abfd, amt); 86 | + if (!x_fatrec_ptr) 87 | + goto got_no_match; 88 | + 89 | + if (bfd_bread (x_fatrec_ptr, amt, abfd) != amt) 90 | + { 91 | + if (bfd_get_error () != bfd_error_system_call) 92 | + goto got_wrong_format_error; 93 | + else 94 | + goto got_no_match; 95 | + } 96 | + 97 | + for (fatindex = 0; fatindex < x_fathdr->num_records; fatindex++) 98 | + { 99 | + const FatElf_External_Record *x_fatrec = &x_fatrec_ptr[fatindex]; 100 | + const unsigned short fatmachine = bfd_getl16(&x_fatrec->machine); 101 | + bfd_uint64_t ui64_offset = 0; 102 | + 103 | + /* most of these tests are more involved in the real ELF header. */ 104 | + if (x_fatrec->word_size != ELFCLASS) 105 | + continue; 106 | + else if (x_fatrec->osabi != ebd->elf_osabi) 107 | + continue; 108 | + 109 | + if (ebd->elf_machine_code != fatmachine 110 | + && (ebd->elf_machine_alt1 == 0 111 | + || fatmachine != ebd->elf_machine_alt1) 112 | + && (ebd->elf_machine_alt2 == 0 113 | + || fatmachine != ebd->elf_machine_alt2)) 114 | + continue; 115 | + 116 | + switch (x_fatrec->byte_order) 117 | + { 118 | + case ELFDATA2MSB: /* Big-endian */ 119 | + if (! bfd_header_big_endian (abfd)) 120 | + continue; 121 | + break; 122 | + case ELFDATA2LSB: /* Little-endian */ 123 | + if (! bfd_header_little_endian (abfd)) 124 | + continue; 125 | + break; 126 | + default: /* Unknown data encoding specified */ 127 | + continue; 128 | + } 129 | + 130 | + ui64_offset = bfd_getl64(&x_fatrec->offset); 131 | + base_offset = (bfd_vma) ui64_offset; 132 | + if ((ui64_offset + bfd_getl64(&x_fatrec->size)) < ui64_offset) 133 | + continue; 134 | + 135 | + if (x_fatrec->word_size == ELFCLASS32) 136 | + { 137 | + if ((ui64_offset + bfd_getl64(&x_fatrec->size)) > 0xFFFFFFFF) 138 | + continue; 139 | + } 140 | + 141 | + break; /* we can use this record! */ 142 | + } 143 | + 144 | + if (fatindex == x_fathdr->num_records) /* no match. */ 145 | + goto got_wrong_format_error; 146 | + 147 | + if (base_offset != (bfd_vma) ((file_ptr) base_offset)) 148 | + goto got_wrong_format_error; 149 | + 150 | + /* Now future seeks will refer to this specific ELF binary. */ 151 | + abfd->base_offset = (ufile_ptr) base_offset; 152 | + if (bfd_seek (abfd, 0, SEEK_SET) != 0) 153 | + goto got_no_match; 154 | + 155 | + /* pull in the actual ELF header and continue as usual. */ 156 | + if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) 157 | + { 158 | + if (bfd_get_error () != bfd_error_system_call) 159 | + goto got_wrong_format_error; 160 | + else 161 | + goto got_no_match; 162 | + } 163 | + } 164 | + 165 | /* Now check to see if we have a valid ELF file, and one that BFD can 166 | make use of. The magic number must match, the address size ('class') 167 | and byte-swapping must match our XVEC entry, and it must have a 168 | @@ -569,10 +670,6 @@ 169 | if (i_ehdrp->e_shoff == 0 && i_ehdrp->e_shnum != 0) 170 | goto got_wrong_format_error; 171 | 172 | - ebd = get_elf_backend_data (abfd); 173 | - if (ebd->s->arch_size != ARCH_SIZE) 174 | - goto got_wrong_format_error; 175 | - 176 | /* Check that the ELF e_machine field matches what this particular 177 | BFD format expects. */ 178 | if (ebd->elf_machine_code != i_ehdrp->e_machine 179 | diff -ruBb gdb-7.8-orig/include/elf/external.h gdb-7.8/include/elf/external.h 180 | --- gdb-7.8-orig/include/elf/external.h 2014-06-11 09:34:41.000000000 -0700 181 | +++ gdb-7.8/include/elf/external.h 2015-02-27 23:32:33.726072007 -0800 182 | @@ -284,4 +284,35 @@ 183 | 184 | #define GRP_ENTRY_SIZE 4 185 | 186 | + 187 | +/* FatELF support. */ 188 | + 189 | +/* This is little endian on disk, and looks like "FA700E1F" in a hex editor. */ 190 | +#define FATELF_MAGIC (0x1F0E70FA) 191 | +#define FATELF_FORMAT_VERSION (1) 192 | + 193 | +/* Values on disk are always littleendian, and align like Elf64. */ 194 | +typedef struct 195 | +{ 196 | + unsigned char machine[2]; /* maps to e_machine. */ 197 | + unsigned char osabi; /* maps to e_ident[EI_OSABI]. */ 198 | + unsigned char osabi_version; /* maps to e_ident[EI_ABIVERSION]. */ 199 | + unsigned char word_size; /* maps to e_ident[EI_CLASS]. */ 200 | + unsigned char byte_order; /* maps to e_ident[EI_DATA]. */ 201 | + unsigned char reserved0; 202 | + unsigned char reserved1; 203 | + unsigned char offset[8]; 204 | + unsigned char size[8]; 205 | +} FatElf_External_Record; 206 | + 207 | +/* Values on disk are always littleendian, and align like Elf64. */ 208 | +typedef struct 209 | +{ 210 | + unsigned char magic[4]; /* always FATELF_MAGIC */ 211 | + unsigned char version[2]; /* latest is always FATELF_FORMAT_VERSION */ 212 | + unsigned char num_records; 213 | + unsigned char reserved0; 214 | +} FatElf_External_Hdr; 215 | + 216 | + 217 | #endif /* _ELF_EXTERNAL_H */ 218 | 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FatELF 2 | 3 | The latest information about FatELF can be found at https://icculus.org/fatelf/ 4 | 5 | ## What is this? 6 | 7 | FatELF is a simple file format that allows you to package several ELF binaries 8 | in one file. The most obvious use for this is supplying a single executable 9 | that will run on different processors; a common scenario would be to pack 10 | both an amd64 and an x86 binary into one file, and let the operating system 11 | choose the correct one at runtime. FatELF can be used with both executable 12 | files and shared libraries. 13 | 14 | At this time, this documentation assumes a GNU/Linux system, but FatELF could 15 | theoretically be of use to most modern Unix systems that use ELF binaries. 16 | FatELF is of no use to Windows, as its EXE files are not ELF format. Mac OS X, 17 | while it has a Unix heritage, does not use ELF either, but their Mach-O 18 | format provides something similar to FatELF (Apple refers to this technology 19 | as "Universal Binaries." It is incompatible with FatELF.) Systems like 20 | FreeBSD and OpenSolaris use ELF binaries, and could theoretically be made 21 | to support FatELF as well. 22 | 23 | 24 | ## Source code licensing information: 25 | 26 | Patches are contributed under their original licenses. For example, the Linux 27 | kernel patch is GPLv2, the binutils patch is GPLv3, and the glibc patch is 28 | LGPL. 29 | 30 | The command line utilities (fatelf-glue, etc) are public domain. 31 | 32 | 33 | ## Using FatELF as an end-user: 34 | 35 | If you're an end-user that just wants to run a FatELF binary that someone 36 | gave you, you have two options. If you want everything to run smoothly, so 37 | you run the FatELF files like any other binary, you need to patch your 38 | system if it doesn't already have FatELF support. It's possible your Linux 39 | distribution already did this for you. If not, GNU/Linux systems will need 40 | the patches for the Linux kernel and glibc. Once you have these in place, 41 | if you just want to run FatELF binaries, you're done. Have fun! 42 | 43 | If you want file(1) to recognize FatELF binaries instead of calling them 44 | "data", you'll want that patch, too. 45 | 46 | If you can't patch your system, you can use the command line tools to extract 47 | the specific ELF file you need, and run that instead. See the "building the 48 | command line tools" section, then try running this: 49 | 50 | fatelf-split my_fatelf_binary 51 | 52 | If the FatELF file contained x86 and amd64 binaries, you'll end up with files 53 | named "my_fatelf_binary-i386" and "my_fatelf_binary-x86_64". Use whichever 54 | you need at this point like any other program. Another option is to extract 55 | just the binary you need, like this... 56 | 57 | fatelf-extract my_elf_binary my_fatelf_binary x86_64 58 | 59 | ...this will extract the amd64 ELF binary from my_fatelf_binary, and place it 60 | in the file "my_elf_binary". 61 | 62 | 63 | ## Using FatELF as a developer: 64 | 65 | If you're a developer that wants to work with FatELF files, you will want to 66 | have your system patched (Linux kernel, glibc), so that you can run FatELF 67 | binaries directly. You may want to patch binutils and gdb, too, but this is 68 | only necessary if you want to link directly against a FatELF library or 69 | debug a FatELF binary/library. In many cases, you can get away 70 | without this functionality. You'll want to get the command line tools 71 | installed (see the "Building the command line tools" section). 72 | 73 | The most common workflow is usually to build your software for all platforms, 74 | separately, and then use fatelf-glue to create FatELF files out of the 75 | separate ELF binaries. So long as the soname doesn't change, it is safe to 76 | link against an ELF shared library and then later turn that shared library 77 | into a FatELF file. The system loaders will still do the right thing. 78 | Alternately, if you patched binutils, you can create the FatELF shared 79 | library first, and then link against it as normal. 80 | 81 | In many cases, you only care about FatELF when you are ready to ship your 82 | binaries to the outside world, so it's possible to simply use fatelf-glue at 83 | the end of the process and never patch a single thing on your development box. 84 | 85 | 86 | ## Using FatELF as a system/tool developer: 87 | 88 | If you are bringing FatELF support to a new platform or development tool, you 89 | should probably examine include/fatelf.h for the data structures, and read 90 | fatelf-specification.txt. The format is not particularly complex. The only 91 | requirement is that your platform support ELF binaries, as that is where 92 | most of the complexity lies. FatELF is just a simple wrapper around 93 | traditional ELF files. The existing command line tools will probably Just 94 | Work on your platform out of the box. 95 | 96 | Please drop Ryan a line at icculus@icculus.org if you add FatELF support to 97 | your software, so he can post a link to it on the FatELF website. 98 | 99 | 100 | ## Building the command line tools: 101 | 102 | You will need to have a system set up for compiling C code, and you will need 103 | [CMake](https://www.cmake.org/). If you are looking for the latest and 104 | greatest version of the tools, you'll need git to download them. If you're 105 | installing from a source tarball, git isn't necessary. 106 | 107 | If you're on a Debian or Ubuntu system, you can probably run this to prepare: 108 | 109 | sudo apt-get install build-essential cmake git 110 | 111 | Once you are ready, you should get the source code. If downloading via git, 112 | this command line should do: 113 | 114 | git clone https://github.com/icculus/fatelf 115 | 116 | If you are using a source tarball, just extract it. 117 | 118 | Now make a build directory, configure the build, and compile the sources: 119 | 120 | mkdir fatelf-build 121 | cd fatelf-build 122 | cmake ../fatelf 123 | make 124 | 125 | You should end up with a pile of binaries, with names like "fatelf-glue" and 126 | "fatelf-info", etc. If you want to install them system-wide, you can do so 127 | now: 128 | 129 | sudo make install 130 | 131 | (`sudo make install DESTDIR=/some/other/path` also works.) 132 | 133 | 134 | ## Using the command line tools: 135 | 136 | Most of the tools expect command line arguments in some form like... 137 | 138 | fatelf-COMMAND OUTPUT INPUT TARGET 139 | 140 | ...where `COMMAND` is the tool to run, `OUTPUT` is the file you want to create 141 | with the results of the operation, `INPUT` is the file you want to process, 142 | and `TARGET` is the target platform. Please note that output files will 143 | overwrite existing files of the same name without warning. 144 | 145 | `TARGET` takes the form of either a specific record number in the form 146 | "recordX" where X is the index of the record in the FatELF file ("record0" is 147 | the first record, "record1" the next, etc), or a formal target name. Formal 148 | names look like this: "x86_64:64bits:le:sysv:osabiver0" ... that's a real 149 | mouthful! All of the fields in a target name are optional. The only 150 | requirement is that the name be unique enough to only refer to a single 151 | record in a given FatELF file. In most cases, you'll only need the machine 152 | architecture; if you have a FatELF file with x86 and amd64 ELF binaries, your 153 | target names can be, simply, "i386" and "x86_64". If you have two SPARC 154 | binaries that are only separated by word size, you could do "32bits" and 155 | "64bits", but if you added an amd64 binary to that FatELF file, you'd need 156 | to do "sparc:64bits" to stay unique. Two PowerPC binaries, one for bigendian 157 | mode and one for little endian, could say "le" or "be" to be unique. If you 158 | want the full target name for a given record, fatelf-info will list them for 159 | you. 160 | 161 | 162 | 163 | The actual tools are: 164 | 165 | fatelf-glue OUTPUT INPUT1 INPUT2 [... INPUTn] 166 | 167 | This takes the ELF binaries listed on the command line (as `INPUT*`), and 168 | glues them together into a FatELF binary named `OUTPUT`. The files' ELF 169 | headers are read to construct the proper FatELF data structures. It is an 170 | error to try to glue two ELF binaries with the same target together, and 171 | fatelf-glue will refuse to do so. 172 | 173 | 174 | fatelf-info INPUT 175 | 176 | Report interesting information about FatELF file `INPUT`. This will list 177 | all fields of all FatELF records, and the full formal target name for 178 | each. 179 | 180 | 181 | fatelf-extract OUTPUT INPUT TARGET 182 | 183 | Extract a copy of the ELF binary that matches `TARGET` from FatELF file `INPUT`, 184 | and write it to `OUTPUT`. If `TARGET` is ambiguous, this operation fails. 185 | 186 | 187 | fatelf-remove OUTPUT INPUT TARGET 188 | 189 | Remove the ELF binary that matches `TARGET` from FatELF file INPUT`, 190 | and write a new FatELF file that lacks that ELF binary to `OUTPUT`. 191 | If `TARGET` is ambiguous, this operation fails. 192 | 193 | 194 | fatelf-replace OUTPUT INPUT NEWELF 195 | 196 | Replace an ELF binary in FatELF file `INPUT` with the one in file `NEWELF`, 197 | and write a new FatELF file with the replacement made. This tool figures 198 | out which binary to replace by reading the headers in `NEWELF`. 199 | 200 | 201 | fatelf-split INPUT 202 | 203 | Split FatELF file `INPUT` into multiple ELF files, one per included target. 204 | The files will be named `INPUT-targetname`, where `targetname` is a formal 205 | target name in the shortest form possible that prevents ambiguity between 206 | included targets. This can overwrite existing files in the same directory 207 | as `INPUT` without warning, so use with caution. fatelf-extract can be a 208 | safer alternative. 209 | 210 | 211 | fatelf-verify INPUT TARGET 212 | 213 | Check if there is an ELF binary in FatELF file `INPUT` that matches the 214 | target name `TARGET`, and set the process exit code appropriately. This 215 | reports zero if `TARGET` was found, and non-zero if not. If `TARGET` is 216 | ambiguous, this is considered an error, and non-zero is reported. 217 | 218 | 219 | fatelf-validate INPUT 220 | 221 | Run several tests on FatELF file `INPUT` to make sure the data is consistent 222 | and sane. This will return non-zero if there are problems detected, or 223 | zero if the tool believes that the FatELF file is correctly formed. Please 224 | note that this is meant to be a sanity check and debugging aid, but will 225 | not detect most forms of file corruption, either intentional or accidental. 226 | 227 | 228 | -------------------------------------------------------------------------------- /patches/linux-kernel.diff: -------------------------------------------------------------------------------- 1 | 2 | 3 | Please note that this patch applies cleanly to Ubuntu 14.10's Linux kernel 4 | sources (3.16, specifically). 5 | 6 | Patches being submitted for consideration on the Linux kernel mailing list 7 | are not kept here, and are made against the current mainline (3.19 at the 8 | time of this writing). If you want those, get them from the mailing 9 | list. 10 | 11 | You probably don't want the below patch unless you're experimenting with a 12 | stable (and older) kernel. 13 | 14 | 15 | diff -ruBb linux-3.16.0-orig/fs/binfmt_elf.c linux-3.16.0/fs/binfmt_elf.c 16 | --- linux-3.16.0-orig/fs/binfmt_elf.c 2014-08-03 15:25:02.000000000 -0700 17 | +++ linux-3.16.0/fs/binfmt_elf.c 2015-03-01 20:04:12.561648371 -0800 18 | @@ -47,7 +47,7 @@ 19 | 20 | static int load_elf_binary(struct linux_binprm *bprm); 21 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, 22 | - int, int, unsigned long); 23 | + int, int, unsigned long, unsigned long); 24 | 25 | #ifdef CONFIG_USELIB 26 | static int load_elf_library(struct file *); 27 | @@ -334,7 +334,7 @@ 28 | 29 | static unsigned long elf_map(struct file *filep, unsigned long addr, 30 | struct elf_phdr *eppnt, int prot, int type, 31 | - unsigned long total_size) 32 | + unsigned long total_size, unsigned long base_offset) 33 | { 34 | unsigned long map_addr; 35 | unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); 36 | @@ -357,11 +357,12 @@ 37 | */ 38 | if (total_size) { 39 | total_size = ELF_PAGEALIGN(total_size); 40 | - map_addr = vm_mmap(filep, addr, total_size, prot, type, off); 41 | + map_addr = vm_mmap(filep, addr, total_size, prot, type, 42 | + off + base_offset); 43 | if (!BAD_ADDR(map_addr)) 44 | vm_munmap(map_addr+size, total_size-size); 45 | } else 46 | - map_addr = vm_mmap(filep, addr, size, prot, type, off); 47 | + map_addr = vm_mmap(filep, addr, size, prot, type, off + base_offset); 48 | 49 | return(map_addr); 50 | } 51 | @@ -394,7 +395,7 @@ 52 | 53 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, 54 | struct file *interpreter, unsigned long *interp_map_addr, 55 | - unsigned long no_base) 56 | + unsigned long no_base, unsigned long base_offset) 57 | { 58 | struct elf_phdr *elf_phdata; 59 | struct elf_phdr *eppnt; 60 | @@ -432,7 +433,7 @@ 61 | if (!elf_phdata) 62 | goto out; 63 | 64 | - retval = kernel_read(interpreter, interp_elf_ex->e_phoff, 65 | + retval = kernel_read(interpreter, interp_elf_ex->e_phoff + base_offset, 66 | (char *)elf_phdata, size); 67 | error = -EIO; 68 | if (retval != size) { 69 | @@ -468,7 +469,8 @@ 70 | load_addr = -vaddr; 71 | 72 | map_addr = elf_map(interpreter, load_addr + vaddr, 73 | - eppnt, elf_prot, elf_type, total_size); 74 | + eppnt, elf_prot, elf_type, total_size, 75 | + base_offset); 76 | total_size = 0; 77 | if (!*interp_map_addr) 78 | *interp_map_addr = map_addr; 79 | @@ -568,6 +570,94 @@ 80 | #endif 81 | } 82 | 83 | +/* 84 | + * See if we're a valid FatELF binary, find the right record, and 85 | + * load (*elf) with the actual ELF header. Sets (*offset) to the 86 | + * base offset of the chosen ELF binary. Returns 0 on success or a negative 87 | + * error code. 88 | + * If we're not a FatELF binary, (*elf) is loaded with the existing contents 89 | + * of (buf) and 0 is returned. 90 | + */ 91 | +static int examine_fatelf(struct file *file, const char *filename, char *buf, 92 | + int buflen, unsigned long *offset, struct elfhdr *elf) 93 | +{ 94 | + int records, i, rc; 95 | + const fatelf_hdr *fatelf = (fatelf_hdr *) buf; 96 | + 97 | + if (likely(le32_to_cpu(fatelf->magic) != FATELF_MAGIC)) { 98 | + *elf = *((struct elfhdr *)buf); /* treat like normal ELF. */ 99 | + return 0; /* not a FatELF binary; not an error. */ 100 | + } else if (unlikely(le16_to_cpu(fatelf->version) != 1)) { 101 | + return -ENOEXEC; /* Unrecognized format version. */ 102 | + } 103 | + 104 | + /* 105 | + * In theory, there could be 255 separate records packed into this 106 | + * binary, but for now, bprm->buf (128 bytes) holds exactly 5 107 | + * records with the fatelf header, and that seems reasonable for 108 | + * most uses. We could add the complexity to read more records later 109 | + * if there's a serious need. 110 | + */ 111 | + records = (int) fatelf->num_records; /* uint8, no byteswap needed */ 112 | + 113 | + if (unlikely(records > 5)) { 114 | + records = 5; /* clamp, in case we find one we can use. */ 115 | + } 116 | + 117 | + for (i = 0; i < records; i++) { 118 | + const fatelf_record *record = &fatelf->records[i]; 119 | + const __u8 osabi = record->osabi; 120 | + const int abiok = likely( likely(osabi == ELFOSABI_NONE) || 121 | + unlikely(osabi == ELFOSABI_LINUX) ); 122 | + 123 | + /* Fill in the data elf_check_arch() might care about. */ 124 | + elf->e_ident[EI_OSABI] = record->osabi; 125 | + elf->e_ident[EI_CLASS] = record->word_size; 126 | + elf->e_ident[EI_DATA] = record->byte_order; 127 | + elf->e_machine = le16_to_cpu(record->machine); 128 | + 129 | + if (likely(!elf_check_arch(elf))) { 130 | + continue; /* Unsupported CPU architecture. */ 131 | + } else if (unlikely(!abiok)) { 132 | + continue; /* Unsupported OS ABI. */ 133 | + } else if (unlikely(record->osabi_version != 0)) { 134 | + continue; /* Unsupported OS ABI version. */ 135 | + } else { 136 | + /* We can support this ELF arch/abi. */ 137 | + const __u64 rec_offset = le64_to_cpu(record->offset); 138 | + const __u64 rec_size = le64_to_cpu(record->size); 139 | + const __u64 end_offset = rec_offset + rec_size; 140 | + const unsigned long uloff = (unsigned long) rec_offset; 141 | + 142 | + if (unlikely(end_offset < rec_offset)) { 143 | + continue; /* overflow (corrupt file?) */ 144 | + } else if (unlikely(ELF_PAGEOFFSET(uloff) != 0)) { 145 | + continue; /* bad alignment. */ 146 | + } 147 | + 148 | +#if BITS_PER_LONG == 32 149 | + if (unlikely(end_offset > 0xFFFFFFFF)) { 150 | + continue; 151 | + } 152 | +#endif 153 | + 154 | + /* replace the FatELF data with the real ELF header. */ 155 | + rc = kernel_read(file, uloff, (char*) elf, sizeof(*elf)); 156 | + if (unlikely((rc != sizeof(*elf)) && (rc >= 0))) { 157 | + rc = -EIO; 158 | + } else if (likely(rc == sizeof(*elf))) { 159 | + *offset = uloff; 160 | + rc = 0; 161 | + } 162 | + 163 | + return rc; 164 | + } 165 | + } 166 | + 167 | + return -ENOEXEC; /* no binaries we could use. */ 168 | +} 169 | + 170 | + 171 | static int load_elf_binary(struct linux_binprm *bprm) 172 | { 173 | struct file *interpreter = NULL; /* to shut gcc up */ 174 | @@ -579,6 +669,8 @@ 175 | unsigned long elf_bss, elf_brk; 176 | int retval, i; 177 | unsigned int size; 178 | + unsigned long base_offset = 0; 179 | + unsigned long interp_base_offset = 0; 180 | unsigned long elf_entry; 181 | unsigned long interp_load_addr = 0; 182 | unsigned long start_code, end_code, start_data, end_data; 183 | @@ -596,8 +688,11 @@ 184 | goto out_ret; 185 | } 186 | 187 | - /* Get the exec-header */ 188 | - loc->elf_ex = *((struct elfhdr *)bprm->buf); 189 | + retval = examine_fatelf(bprm->file, bprm->filename, bprm->buf, 190 | + BINPRM_BUF_SIZE, &base_offset, &loc->elf_ex); 191 | + if (unlikely(retval < 0)) { 192 | + goto out_ret; 193 | + } 194 | 195 | retval = -ENOEXEC; 196 | /* First of all, some simple consistency checks */ 197 | @@ -623,7 +718,7 @@ 198 | if (!elf_phdata) 199 | goto out; 200 | 201 | - retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, 202 | + retval = kernel_read(bprm->file, loc->elf_ex.e_phoff + base_offset, 203 | (char *)elf_phdata, size); 204 | if (retval != size) { 205 | if (retval >= 0) 206 | @@ -657,7 +752,8 @@ 207 | if (!elf_interpreter) 208 | goto out_free_ph; 209 | 210 | - retval = kernel_read(bprm->file, elf_ppnt->p_offset, 211 | + retval = kernel_read(bprm->file, 212 | + elf_ppnt->p_offset + base_offset, 213 | elf_interpreter, 214 | elf_ppnt->p_filesz); 215 | if (retval != elf_ppnt->p_filesz) { 216 | @@ -690,8 +786,13 @@ 217 | goto out_free_dentry; 218 | } 219 | 220 | - /* Get the exec headers */ 221 | - loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); 222 | + retval = examine_fatelf(interpreter, elf_interpreter, 223 | + bprm->buf, BINPRM_BUF_SIZE, 224 | + &interp_base_offset, 225 | + &loc->interp_elf_ex); 226 | + if (unlikely(retval < 0)) { 227 | + goto out_free_dentry; 228 | + } 229 | break; 230 | } 231 | elf_ppnt++; 232 | @@ -818,7 +919,7 @@ 233 | } 234 | 235 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, 236 | - elf_prot, elf_flags, 0); 237 | + elf_prot, elf_flags, 0, base_offset); 238 | if (BAD_ADDR(error)) { 239 | send_sig(SIGKILL, current, 0); 240 | retval = IS_ERR((void *)error) ? 241 | @@ -899,7 +1000,7 @@ 242 | elf_entry = load_elf_interp(&loc->interp_elf_ex, 243 | interpreter, 244 | &interp_map_addr, 245 | - load_bias); 246 | + load_bias, interp_base_offset); 247 | if (!IS_ERR((void *)elf_entry)) { 248 | /* 249 | * load_elf_interp() returns relocation 250 | @@ -1016,11 +1117,19 @@ 251 | unsigned long elf_bss, bss, len; 252 | int retval, error, i, j; 253 | struct elfhdr elf_ex; 254 | + unsigned long base_offset = 0; 255 | + char buf[BINPRM_BUF_SIZE]; 256 | 257 | - error = -ENOEXEC; 258 | - retval = kernel_read(file, 0, (char *)&elf_ex, sizeof(elf_ex)); 259 | - if (retval != sizeof(elf_ex)) 260 | + retval = kernel_read(file, 0, buf, sizeof(buf)); 261 | + if (unlikely(retval != sizeof(buf))) { 262 | + error = (retval >= 0) ? -EIO : retval; 263 | goto out; 264 | + } 265 | + error = examine_fatelf(file, 0, buf, sizeof(buf), &base_offset, &elf_ex); 266 | + if (unlikely(retval < 0)) { 267 | + goto out; 268 | + } 269 | + error = -ENOEXEC; 270 | 271 | if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) 272 | goto out; 273 | @@ -1042,7 +1151,8 @@ 274 | 275 | eppnt = elf_phdata; 276 | error = -ENOEXEC; 277 | - retval = kernel_read(file, elf_ex.e_phoff, (char *)eppnt, j); 278 | + retval = kernel_read(file, elf_ex.e_phoff + base_offset, 279 | + (char *)eppnt, j); 280 | if (retval != j) 281 | goto out_free_ph; 282 | 283 | @@ -1063,7 +1173,7 @@ 284 | PROT_READ | PROT_WRITE | PROT_EXEC, 285 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, 286 | (eppnt->p_offset - 287 | - ELF_PAGEOFFSET(eppnt->p_vaddr))); 288 | + ELF_PAGEOFFSET(eppnt->p_vaddr)) + base_offset); 289 | if (error != ELF_PAGESTART(eppnt->p_vaddr)) 290 | goto out_free_ph; 291 | 292 | diff -ruBb linux-3.16.0-orig/include/uapi/linux/elf.h linux-3.16.0/include/uapi/linux/elf.h 293 | --- linux-3.16.0-orig/include/uapi/linux/elf.h 2014-08-03 15:25:02.000000000 -0700 294 | +++ linux-3.16.0/include/uapi/linux/elf.h 2015-03-01 20:02:48.341645861 -0800 295 | @@ -414,4 +414,27 @@ 296 | Elf64_Word n_type; /* Content type */ 297 | } Elf64_Nhdr; 298 | 299 | +/* FatELF (multiple ELF binaries in one file) support */ 300 | +#define FATELF_MAGIC (0x1F0E70FA) 301 | + 302 | +typedef struct fatelf_record { 303 | + __le16 machine; /* maps to e_machine */ 304 | + __u8 osabi; /* maps to e_ident[EI_OSABI] */ 305 | + __u8 osabi_version; /* maps to e_ident[EI_ABIVERSION] */ 306 | + __u8 word_size; /* maps to e_ident[EI_CLASS] */ 307 | + __u8 byte_order; /* maps to e_ident[EI_DATA] */ 308 | + __u8 reserved0; 309 | + __u8 reserved1; 310 | + __le64 offset; 311 | + __le64 size; 312 | +} fatelf_record; 313 | + 314 | +typedef struct fatelf_hdr { 315 | + __le32 magic; 316 | + __le16 version; 317 | + __u8 num_records; 318 | + __u8 reserved0; 319 | + fatelf_record records[]; 320 | +} fatelf_hdr; 321 | + 322 | #endif /* _UAPI_LINUX_ELF_H */ 323 | diff -ruBb linux-3.16.0-orig/kernel/module.c linux-3.16.0/kernel/module.c 324 | --- linux-3.16.0-orig/kernel/module.c 2015-03-01 19:57:06.000000000 -0800 325 | +++ linux-3.16.0/kernel/module.c 2015-03-01 20:02:48.341645861 -0800 326 | @@ -172,7 +172,8 @@ 327 | EXPORT_SYMBOL(unregister_module_notifier); 328 | 329 | struct load_info { 330 | - Elf_Ehdr *hdr; 331 | + Elf_Ehdr *hdr_alloc; /* returned from vmalloc */ 332 | + Elf_Ehdr *hdr; /* adjusted hdr_alloc for FatELF */ 333 | unsigned long len; 334 | Elf_Shdr *sechdrs; 335 | char *secstrings, *strtab; 336 | @@ -2485,6 +2486,61 @@ 337 | return 0; 338 | } 339 | 340 | +/* 341 | + * See if we're a valid FatELF binary, find the right record, and 342 | + * return the offset of that record within the binary. Returns NULL if there's 343 | + * a problem, or a pointer to the real ELF header if we're okay. 344 | + * If we don't see the FatELF magic number, we assume this is a regular ELF 345 | + * binary and let the regular ELF checks handle it. 346 | + * 347 | + * This is a simplified version of examine_fatelf in fs/binfmt_elf.c 348 | + */ 349 | +static Elf_Ehdr *examine_fatelf_module(const unsigned char *hdr, 350 | + const unsigned long len) 351 | +{ 352 | + Elf_Ehdr elf; 353 | + int records, i; 354 | + const fatelf_hdr *fatelf = (const fatelf_hdr *) hdr; 355 | + 356 | + if (likely(le32_to_cpu(fatelf->magic) != FATELF_MAGIC)) { 357 | + return (Elf_Ehdr *) hdr; /* not FatELF; not an error. */ 358 | + } else if (unlikely(le16_to_cpu(fatelf->version) != 1)) { 359 | + return NULL; /* Unrecognized format version. */ 360 | + } 361 | + 362 | + memset(&elf, 0, sizeof (elf)); 363 | + 364 | + records = (int) fatelf->num_records; /* uint8, no byteswap needed */ 365 | + for (i = 0; i < records; i++) { 366 | + const fatelf_record *record = &fatelf->records[i]; 367 | + 368 | + /* Fill in the data elf_check_arch() might care about. */ 369 | + elf.e_ident[EI_OSABI] = record->osabi; 370 | + elf.e_ident[EI_CLASS] = record->word_size; 371 | + elf.e_ident[EI_DATA] = record->byte_order; 372 | + elf.e_machine = le16_to_cpu(record->machine); 373 | + 374 | + if (likely(!elf_check_arch(&elf))) { 375 | + continue; /* Unsupported CPU architecture. */ 376 | + } else { 377 | + const __u64 rec_offset = le64_to_cpu(record->offset); 378 | + const __u64 rec_size = le64_to_cpu(record->size); 379 | + const __u64 end_offset = rec_offset + rec_size; 380 | + const unsigned long uloff = (unsigned long) rec_offset; 381 | + 382 | + if (unlikely(end_offset < rec_offset)) { 383 | + continue; /* overflow (corrupt file?)... */ 384 | + } else if (unlikely(end_offset > len)) { 385 | + continue; /* past EOF. */ 386 | + } 387 | + 388 | + return (Elf_Ehdr *) (hdr + uloff); 389 | + } 390 | + } 391 | + 392 | + return NULL; /* no binaries we could use. */ 393 | +} 394 | + 395 | /* Sets info->hdr and info->len. */ 396 | static int copy_module_from_user(const void __user *umod, unsigned long len, 397 | struct load_info *info) 398 | @@ -2500,15 +2556,22 @@ 399 | return err; 400 | 401 | /* Suck in entire file: we'll want most of it. */ 402 | - info->hdr = vmalloc(info->len); 403 | - if (!info->hdr) 404 | + info->hdr_alloc = vmalloc(info->len); 405 | + if (!info->hdr_alloc) 406 | return -ENOMEM; 407 | 408 | - if (copy_from_user(info->hdr, umod, info->len) != 0) { 409 | - vfree(info->hdr); 410 | + if (copy_from_user(info->hdr_alloc, umod, info->len) != 0) { 411 | + vfree(info->hdr_alloc); 412 | return -EFAULT; 413 | } 414 | 415 | + /* returns the actual ELF header (whether or not this was FatELF). */ 416 | + info->hdr = examine_fatelf_module((unsigned char *) info->hdr_alloc, info->len); 417 | + if (info->hdr == NULL) { 418 | + vfree(info->hdr_alloc); 419 | + return -ENOEXEC; 420 | + } 421 | + 422 | return 0; 423 | } 424 | 425 | @@ -2543,18 +2606,18 @@ 426 | goto out; 427 | } 428 | 429 | - info->hdr = vmalloc(stat.size); 430 | - if (!info->hdr) { 431 | + info->hdr_alloc = vmalloc(stat.size); 432 | + if (!info->hdr_alloc) { 433 | err = -ENOMEM; 434 | goto out; 435 | } 436 | 437 | pos = 0; 438 | while (pos < stat.size) { 439 | - bytes = kernel_read(f.file, pos, (char *)(info->hdr) + pos, 440 | + bytes = kernel_read(f.file, pos, (char *)(info->hdr_alloc) + pos, 441 | stat.size - pos); 442 | if (bytes < 0) { 443 | - vfree(info->hdr); 444 | + vfree(info->hdr_alloc); 445 | err = bytes; 446 | goto out; 447 | } 448 | @@ -2564,6 +2627,14 @@ 449 | } 450 | info->len = pos; 451 | 452 | + /* returns the actual ELF header (whether or not this was FatELF). */ 453 | + info->hdr = examine_fatelf_module((unsigned char *) info->hdr_alloc, info->len); 454 | + if (info->hdr == NULL) { 455 | + vfree(info->hdr_alloc); 456 | + err = -ENOEXEC; 457 | + goto out; 458 | + } 459 | + 460 | out: 461 | fdput(f); 462 | return err; 463 | @@ -2571,7 +2642,7 @@ 464 | 465 | static void free_copy(struct load_info *info) 466 | { 467 | - vfree(info->hdr); 468 | + vfree(info->hdr_alloc); 469 | } 470 | 471 | static int rewrite_section_headers(struct load_info *info, int flags) 472 | -------------------------------------------------------------------------------- /patches/binutils.diff: -------------------------------------------------------------------------------- 1 | diff -ruBb binutils-2.24.90.20141014-orig/bfd/bfd.c binutils-2.24.90.20141014/bfd/bfd.c 2 | --- binutils-2.24.90.20141014-orig/bfd/bfd.c 2014-07-04 02:51:31.000000000 -0700 3 | +++ binutils-2.24.90.20141014/bfd/bfd.c 2015-02-27 21:20:16.069835438 -0800 4 | @@ -200,6 +200,10 @@ 5 | . {* Set if this is the linker output BFD. *} 6 | . unsigned int is_linker_output : 1; 7 | . 8 | +. {* Base offset, in bytes, of object inside a container file, such as FatELF, 9 | +. or a Mach-O Universal Binary. This will be zero for most things. *} 10 | +. ufile_ptr base_offset; 11 | +. 12 | . {* Currently my_archive is tested before adding origin to 13 | . anything. I believe that this can become always an add of 14 | . origin, with origin set to 0 for non archive files. *} 15 | diff -ruBb binutils-2.24.90.20141014-orig/bfd/bfd-in2.h binutils-2.24.90.20141014/bfd/bfd-in2.h 16 | --- binutils-2.24.90.20141014-orig/bfd/bfd-in2.h 2014-09-17 18:36:55.000000000 -0700 17 | +++ binutils-2.24.90.20141014/bfd/bfd-in2.h 2015-02-27 21:18:57.193833087 -0800 18 | @@ -6430,6 +6430,10 @@ 19 | /* Set if this is the linker output BFD. */ 20 | unsigned int is_linker_output : 1; 21 | 22 | + /* Base offset, in bytes, of object inside a container file, such as FatELF, 23 | + or a Mach-O Universal Binary. This will be zero for most things. */ 24 | + ufile_ptr base_offset; 25 | + 26 | /* Currently my_archive is tested before adding origin to 27 | anything. I believe that this can become always an add of 28 | origin, with origin set to 0 for non archive files. */ 29 | diff -ruBb binutils-2.24.90.20141014-orig/bfd/bfdio.c binutils-2.24.90.20141014/bfd/bfdio.c 30 | --- binutils-2.24.90.20141014-orig/bfd/bfdio.c 2014-03-26 01:28:52.000000000 -0700 31 | +++ binutils-2.24.90.20141014/bfd/bfdio.c 2015-02-27 21:23:09.953840620 -0800 32 | @@ -311,6 +311,9 @@ 33 | 34 | file_position = position; 35 | if (direction == SEEK_SET) 36 | + file_position += abfd->base_offset; 37 | + 38 | + if (direction == SEEK_SET) 39 | { 40 | bfd *parent_bfd = abfd; 41 | 42 | @@ -347,7 +350,7 @@ 43 | { 44 | /* Adjust `where' field. */ 45 | if (direction == SEEK_SET) 46 | - abfd->where = position; 47 | + abfd->where = position + abfd->base_offset; 48 | else 49 | abfd->where += position; 50 | } 51 | diff -ruBb binutils-2.24.90.20141014-orig/bfd/elfcode.h binutils-2.24.90.20141014/bfd/elfcode.h 52 | --- binutils-2.24.90.20141014-orig/bfd/elfcode.h 2014-09-18 10:24:41.000000000 -0700 53 | +++ binutils-2.24.90.20141014/bfd/elfcode.h 2015-02-27 21:24:25.753842879 -0800 54 | @@ -497,6 +496,12 @@ 55 | asection *s; 56 | bfd_size_type amt; 57 | const bfd_target *target; 58 | + const FatElf_External_Hdr *x_fathdr = (FatElf_External_Hdr *) &x_ehdr; 59 | + bfd_vma base_offset = 0; 60 | + 61 | + ebd = get_elf_backend_data (abfd); 62 | + if (ebd->s->arch_size != ARCH_SIZE) 63 | + goto got_wrong_format_error; 64 | 65 | /* Read in the ELF header in external format. */ 66 | 67 | @@ -508,6 +513,102 @@ 68 | goto got_no_match; 69 | } 70 | 71 | + /* See if this is a FatELF file, and if so, locate the correct record. */ 72 | + if (bfd_getl32(&x_fathdr->magic) == FATELF_MAGIC) 73 | + { 74 | + FatElf_External_Record *x_fatrec_ptr; 75 | + unsigned char fatindex; 76 | + file_ptr seekpos = -((file_ptr) sizeof (x_ehdr)); 77 | + 78 | + if (bfd_getl16(&x_fathdr->version) != FATELF_FORMAT_VERSION) 79 | + goto got_wrong_format_error; 80 | + 81 | + /* reposition at the end of the FatELF header for record reading... */ 82 | + seekpos += ((file_ptr) sizeof (*x_fathdr)); 83 | + if (bfd_seek (abfd, seekpos, SEEK_CUR) != 0) 84 | + goto got_no_match; 85 | + 86 | + amt = sizeof (*x_fatrec_ptr) * x_fathdr->num_records; 87 | + x_fatrec_ptr = (FatElf_External_Record *) bfd_alloc (abfd, amt); 88 | + if (!x_fatrec_ptr) 89 | + goto got_no_match; 90 | + 91 | + if (bfd_bread (x_fatrec_ptr, amt, abfd) != amt) 92 | + { 93 | + if (bfd_get_error () != bfd_error_system_call) 94 | + goto got_wrong_format_error; 95 | + else 96 | + goto got_no_match; 97 | + } 98 | + 99 | + for (fatindex = 0; fatindex < x_fathdr->num_records; fatindex++) 100 | + { 101 | + const FatElf_External_Record *x_fatrec = &x_fatrec_ptr[fatindex]; 102 | + const unsigned short fatmachine = bfd_getl16(&x_fatrec->machine); 103 | + bfd_uint64_t ui64_offset = 0; 104 | + 105 | + /* most of these tests are more involved in the real ELF header. */ 106 | + if (x_fatrec->word_size != ELFCLASS) 107 | + continue; 108 | + else if (x_fatrec->osabi != ebd->elf_osabi) 109 | + continue; 110 | + 111 | + if (ebd->elf_machine_code != fatmachine 112 | + && (ebd->elf_machine_alt1 == 0 113 | + || fatmachine != ebd->elf_machine_alt1) 114 | + && (ebd->elf_machine_alt2 == 0 115 | + || fatmachine != ebd->elf_machine_alt2)) 116 | + continue; 117 | + 118 | + switch (x_fatrec->byte_order) 119 | + { 120 | + case ELFDATA2MSB: /* Big-endian */ 121 | + if (! bfd_header_big_endian (abfd)) 122 | + continue; 123 | + break; 124 | + case ELFDATA2LSB: /* Little-endian */ 125 | + if (! bfd_header_little_endian (abfd)) 126 | + continue; 127 | + break; 128 | + default: /* Unknown data encoding specified */ 129 | + continue; 130 | + } 131 | + 132 | + ui64_offset = bfd_getl64(&x_fatrec->offset); 133 | + base_offset = (bfd_vma) ui64_offset; 134 | + if ((ui64_offset + bfd_getl64(&x_fatrec->size)) < ui64_offset) 135 | + continue; 136 | + 137 | + if (x_fatrec->word_size == ELFCLASS32) 138 | + { 139 | + if ((ui64_offset + bfd_getl64(&x_fatrec->size)) > 0xFFFFFFFF) 140 | + continue; 141 | + } 142 | + 143 | + break; /* we can use this record! */ 144 | + } 145 | + 146 | + if (fatindex == x_fathdr->num_records) /* no match. */ 147 | + goto got_wrong_format_error; 148 | + 149 | + if (base_offset != (bfd_vma) ((file_ptr) base_offset)) 150 | + goto got_wrong_format_error; 151 | + 152 | + /* Now future seeks will refer to this specific ELF binary. */ 153 | + abfd->base_offset = (ufile_ptr) base_offset; 154 | + if (bfd_seek (abfd, 0, SEEK_SET) != 0) 155 | + goto got_no_match; 156 | + 157 | + /* pull in the actual ELF header and continue as usual. */ 158 | + if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) 159 | + { 160 | + if (bfd_get_error () != bfd_error_system_call) 161 | + goto got_wrong_format_error; 162 | + else 163 | + goto got_no_match; 164 | + } 165 | + } 166 | + 167 | /* Now check to see if we have a valid ELF file, and one that BFD can 168 | make use of. The magic number must match, the address size ('class') 169 | and byte-swapping must match our XVEC entry, and it must have a 170 | @@ -569,10 +670,6 @@ 171 | if (i_ehdrp->e_shoff == 0 && i_ehdrp->e_shnum != 0) 172 | goto got_wrong_format_error; 173 | 174 | - ebd = get_elf_backend_data (abfd); 175 | - if (ebd->s->arch_size != ARCH_SIZE) 176 | - goto got_wrong_format_error; 177 | - 178 | /* Check that the ELF e_machine field matches what this particular 179 | BFD format expects. */ 180 | if (ebd->elf_machine_code != i_ehdrp->e_machine 181 | diff -ruBb binutils-2.24.90.20141014-orig/binutils/readelf.c binutils-2.24.90.20141014/binutils/readelf.c 182 | --- binutils-2.24.90.20141014-orig/binutils/readelf.c 2014-10-14 02:28:42.000000000 -0700 183 | +++ binutils-2.24.90.20141014/binutils/readelf.c 2015-02-27 21:38:05.901867322 -0800 184 | @@ -14839,6 +14839,98 @@ 185 | } 186 | 187 | static int 188 | +process_fatelf (char *file_name, FILE *file) 189 | +{ 190 | + FatElf_External_Hdr hdr; 191 | + FatElf_External_Record *rec; 192 | + int ver, recs; 193 | + size_t len; 194 | + int ret; 195 | + int i; 196 | + 197 | + if (fread (&hdr, sizeof (hdr), 1, file) != 1) 198 | + { 199 | + error (_("%s: Failed to read FatELF header\n"), file_name); 200 | + return 1; 201 | + } 202 | + 203 | + ver = (int) byte_get_little_endian(hdr.version, sizeof (hdr.version)); 204 | + if (ver != FATELF_FORMAT_VERSION) 205 | + { 206 | + error (_("%s: Unrecognized FatELF format version %d\n"), file_name, ver); 207 | + return 1; 208 | + } 209 | + 210 | + recs = (int) hdr.num_records; 211 | + printf(_("%s: FatELF version %d, %d records\n"), file_name, ver, recs); 212 | + 213 | + len = sizeof(FatElf_External_Record) * recs; 214 | + rec = (FatElf_External_Record *) malloc(len); 215 | + if (rec == NULL) 216 | + { 217 | + error (_("Out of memory\n")); 218 | + return 1; 219 | + } 220 | + 221 | + if (fread (rec, len, 1, file) != 1) 222 | + { 223 | + free(rec); 224 | + error (_("%s: Failed to read FatELF records\n"), file_name); 225 | + return 1; 226 | + } 227 | + 228 | + for (i = 0; i < recs; i++) 229 | + { 230 | + FatElf_External_Record *r = &rec[i]; 231 | + const int machine = (int) byte_get_little_endian(r->machine, 2); 232 | + 233 | + archive_file_size = (unsigned long) byte_get_little_endian(r->size, 8); 234 | + archive_file_offset = (unsigned long) byte_get_little_endian(r->offset, 8); 235 | + 236 | + printf(_("\n")); 237 | + printf(_("FatELF record #%d:\n"), i); 238 | + 239 | + printf (_(" Machine: %s\n"), 240 | + get_machine_name (machine)); 241 | + printf (_(" OS/ABI: %s\n"), 242 | + get_osabi_name (r->osabi)); 243 | + printf (_(" ABI Version: %d\n"), 244 | + r->osabi_version); 245 | + printf (_(" Class: %s\n"), 246 | + get_elf_class (r->word_size)); 247 | + printf (_(" Data: %s\n"), 248 | + get_data_encoding (r->byte_order)); 249 | + printf (_(" Offset: %lu\n"), 250 | + archive_file_offset); 251 | + printf (_(" Size: %lu\n"), 252 | + archive_file_size); 253 | + printf (_("\n")); 254 | + 255 | + if (!do_archive_index) 256 | + { 257 | + if (fseek (file, archive_file_offset, SEEK_SET)) 258 | + { 259 | + error (_("%s: Unable to seek to 0x%lx\n"), file_name, 260 | + archive_file_offset); 261 | + 262 | + free(rec); 263 | + return 1; 264 | + } 265 | + 266 | + ret = process_object (file_name, file); 267 | + if (ret != 0) 268 | + { 269 | + free(rec); 270 | + return ret; 271 | + } 272 | + } 273 | + } 274 | + 275 | + free(rec); 276 | + return 0; 277 | +} 278 | + 279 | +static int 280 | process_file (char * file_name) 281 | { 282 | FILE * file; 283 | @@ -14876,7 +14968,12 @@ 284 | return 1; 285 | } 286 | 287 | - if (memcmp (armag, ARMAG, SARMAG) == 0) 288 | + if (byte_get_little_endian((unsigned char *) armag, 4) == FATELF_MAGIC) 289 | + { 290 | + rewind (file); 291 | + ret = process_fatelf (file_name, file); 292 | + } 293 | + else if (memcmp (armag, ARMAG, SARMAG) == 0) 294 | ret = process_archive (file_name, file, FALSE); 295 | else if (memcmp (armag, ARMAGT, SARMAG) == 0) 296 | ret = process_archive (file_name, file, TRUE); 297 | diff -ruBb binutils-2.24.90.20141014-orig/elfcpp/elfcpp.h binutils-2.24.90.20141014/elfcpp/elfcpp.h 298 | --- binutils-2.24.90.20141014-orig/elfcpp/elfcpp.h 2014-07-31 04:27:10.000000000 -0700 299 | +++ binutils-2.24.90.20141014/elfcpp/elfcpp.h 2015-02-27 21:17:46.449830979 -0800 300 | @@ -75,6 +75,40 @@ 301 | typedef int64_t Elf_Swxword; 302 | }; 303 | 304 | +// FatELF support. 305 | + 306 | +// The valid values found in FatElfHdr::magic 307 | +const int FATELFMAG0 = 0xFA; 308 | +const int FATELFMAG1 = 0x70; 309 | +const int FATELFMAG2 = 0x0E; 310 | +const int FATELFMAG3 = 0x1F; 311 | + 312 | +// latest supported file format. 313 | +const int FATELF_FORMAT_VERSION = 1; 314 | + 315 | +// FatELF values on disk are always littleendian, and align like Elf64. 316 | + 317 | +struct FatElf_Record 318 | +{ 319 | + unsigned char machine[2]; // maps to e_machine. 320 | + unsigned char osabi; // maps to e_ident[EI_OSABI]. 321 | + unsigned char osabi_version; // maps to e_ident[EI_ABIVERSION]. 322 | + unsigned char word_size; // maps to e_ident[EI_CLASS]. 323 | + unsigned char byte_order; // maps to e_ident[EI_DATA]. 324 | + unsigned char reserved0; 325 | + unsigned char reserved1; 326 | + unsigned char offset[8]; 327 | + unsigned char size[8]; 328 | +}; 329 | + 330 | +struct FatElf_Hdr 331 | +{ 332 | + unsigned char magic[4]; // always FATELFMAG0 .. FATELFMAG3 333 | + unsigned char version[2]; // latest is always FATELF_FORMAT_VERSION 334 | + unsigned char num_records; 335 | + unsigned char reserved0; 336 | +}; 337 | + 338 | // Offsets within the Ehdr e_ident field. 339 | 340 | const int EI_MAG0 = 0; 341 | diff -ruBb binutils-2.24.90.20141014-orig/gold/object.cc binutils-2.24.90.20141014/gold/object.cc 342 | --- binutils-2.24.90.20141014-orig/gold/object.cc 2014-09-30 15:26:28.000000000 -0700 343 | +++ binutils-2.24.90.20141014/gold/object.cc 2015-02-27 21:45:55.013881304 -0800 344 | @@ -3099,12 +3099,124 @@ 345 | 346 | const unsigned char* p = input_file->file().get_view(offset, 0, want, 347 | true, false); 348 | + 349 | + static const unsigned char fatelfmagic[4] = 350 | + { 351 | + elfcpp::FATELFMAG0, elfcpp::FATELFMAG1, 352 | + elfcpp::FATELFMAG2, elfcpp::FATELFMAG3 353 | + }; 354 | + 355 | + if ((want > 4) && (memcmp(p, fatelfmagic, 4) == 0)) 356 | + { 357 | + // This is a FatELF file. Seek to correct ELF object now. 358 | + off_t base_offset = parse_fatelf_records(input_file->filename(), 359 | + input_file, p, want); 360 | + if (base_offset < 0) 361 | + return false; 362 | + 363 | + // read the actual ELF header. 364 | + p = input_file->file().get_view(base_offset + offset, 0, want, 365 | + true, false); 366 | + } 367 | + 368 | *start = p; 369 | *read_size = want; 370 | 371 | return elfcpp::Elf_recognizer::is_elf_file(p, want); 372 | } 373 | 374 | +static inline uint16_t fatelf_convert16(const unsigned char *buf) 375 | +{ 376 | + return ((uint16_t) buf[0]) | (((uint16_t) buf[1]) << 8); 377 | +} 378 | + 379 | +static inline uint64_t fatelf_convert64(const unsigned char *buf) 380 | +{ 381 | + return ( (((uint64_t) buf[0]) << 0) | 382 | + (((uint64_t) buf[1]) << 8) | 383 | + (((uint64_t) buf[2]) << 16) | 384 | + (((uint64_t) buf[3]) << 24) | 385 | + (((uint64_t) buf[4]) << 32) | 386 | + (((uint64_t) buf[5]) << 40) | 387 | + (((uint64_t) buf[6]) << 48) | 388 | + (((uint64_t) buf[7]) << 56) ); 389 | +} 390 | + 391 | +off_t 392 | +parse_fatelf_records(const std::string& name, Input_file* input_file, 393 | + const unsigned char* p, section_offset_type bytes) 394 | +{ 395 | + if ( ((size_t) bytes) < sizeof (elfcpp::FatElf_Hdr) ) 396 | + { 397 | + gold_error(_("%s: FatELF file too short"), name.c_str()); 398 | + return false; 399 | + } 400 | + 401 | + const elfcpp::FatElf_Hdr *fhdr = (elfcpp::FatElf_Hdr *) p; 402 | + const uint16_t version = fatelf_convert16(fhdr->version); 403 | + 404 | + if (version != elfcpp::FATELF_FORMAT_VERSION) 405 | + { 406 | + gold_error(_("%s: Unrecognized FatELF version"), name.c_str()); 407 | + return false; 408 | + } 409 | + 410 | + const off_t filesize = input_file->file().filesize(); 411 | + const int recs = (int) fhdr->num_records; 412 | + const section_size_type read_size = sizeof (elfcpp::FatElf_Record) * recs; 413 | + if ( filesize < ((off_t)(read_size + sizeof (elfcpp::FatElf_Hdr))) ) 414 | + { 415 | + gold_error(_("%s: FatELF file too short"), name.c_str()); 416 | + return false; 417 | + } 418 | + 419 | + const elfcpp::FatElf_Record *rec; 420 | + rec = (elfcpp::FatElf_Record *) input_file->file().get_view(0, 421 | + sizeof (elfcpp::FatElf_Hdr), read_size, 422 | + false, false); 423 | + 424 | + const Target &target = parameters->target(); 425 | + const int target_size = target.get_size(); 426 | + const bool target_big_endian = target.is_big_endian(); 427 | + const elfcpp::EM target_machine = target.machine_code(); 428 | + 429 | + for (int i = 0; i < recs; i++) 430 | + { 431 | + const elfcpp::FatElf_Record *r = &rec[i]; 432 | + const elfcpp::EM machine = (elfcpp::EM) fatelf_convert16(r->machine); 433 | + const uint64_t offset = fatelf_convert64(r->offset); 434 | + const uint64_t size = fatelf_convert64(r->size); 435 | + const uint64_t endpoint = (offset + size); 436 | + const int cls = (int) r->word_size; 437 | + const int endian = (int) r->byte_order; 438 | + 439 | + if (machine != target_machine) 440 | + continue; 441 | + else if (cls != elfcpp::ELFCLASS32 && cls != elfcpp::ELFCLASS64) 442 | + continue; 443 | + else if ((cls == elfcpp::ELFCLASS32) && (target_size != 32)) 444 | + continue; 445 | + else if ((cls == elfcpp::ELFCLASS64) && (target_size != 64)) 446 | + continue; 447 | + else if ((endian != elfcpp::ELFDATA2MSB) && (target_big_endian)) 448 | + continue; 449 | + else if ((endian != elfcpp::ELFDATA2LSB) && (!target_big_endian)) 450 | + continue; 451 | + else if (offset > endpoint) // overflow? 452 | + continue; 453 | + else if (endpoint > ((uint64_t) filesize)) 454 | + continue; 455 | + else if ((target_size == 32) && (endpoint > 0xFFFFFFFF)) 456 | + continue; 457 | + 458 | + // we can use this ELF object! 459 | + return (off_t) offset; 460 | + } 461 | + 462 | + gold_error(_("%s: No compatible FatELF records found"), name.c_str()); 463 | + return (off_t) -1; 464 | +} 465 | + 466 | // Read an ELF file and return the appropriate instance of Object. 467 | 468 | Object* 469 | diff -ruBb binutils-2.24.90.20141014-orig/gold/object.h binutils-2.24.90.20141014/gold/object.h 470 | --- binutils-2.24.90.20141014-orig/gold/object.h 2014-09-03 13:39:34.000000000 -0700 471 | +++ binutils-2.24.90.20141014/gold/object.h 2015-02-27 21:17:46.453830979 -0800 472 | @@ -2906,6 +2906,15 @@ 473 | is_elf_object(Input_file* input_file, off_t offset, 474 | const unsigned char** start, int* read_size); 475 | 476 | +// Parse a FatELF header, and return the base offset of the desired system's 477 | +// ELF binary. Returns -1 on error, or if there isn't a compatible ELF object 478 | +// found, calling gold_error() with specifics. P is BYTES long, and 479 | +// holds the FatELF header. 480 | + 481 | +off_t 482 | +parse_fatelf_records(const std::string& name, Input_file* input_file, 483 | + const unsigned char* p, section_offset_type bytes); 484 | + 485 | // Return an Object appropriate for the input file. P is BYTES long, 486 | // and holds the ELF header. If PUNCONFIGURED is not NULL, then if 487 | // this sees an object the linker is not configured to support, it 488 | diff -ruBb binutils-2.24.90.20141014-orig/include/elf/external.h binutils-2.24.90.20141014/include/elf/external.h 489 | --- binutils-2.24.90.20141014-orig/include/elf/external.h 2014-03-26 01:28:53.000000000 -0700 490 | +++ binutils-2.24.90.20141014/include/elf/external.h 2015-02-27 21:17:46.453830979 -0800 491 | @@ -284,4 +284,35 @@ 492 | 493 | #define GRP_ENTRY_SIZE 4 494 | 495 | + 496 | +/* FatELF support. */ 497 | + 498 | +/* This is little endian on disk, and looks like "FA700E1F" in a hex editor. */ 499 | +#define FATELF_MAGIC (0x1F0E70FA) 500 | +#define FATELF_FORMAT_VERSION (1) 501 | + 502 | +/* Values on disk are always littleendian, and align like Elf64. */ 503 | +typedef struct 504 | +{ 505 | + unsigned char machine[2]; /* maps to e_machine. */ 506 | + unsigned char osabi; /* maps to e_ident[EI_OSABI]. */ 507 | + unsigned char osabi_version; /* maps to e_ident[EI_ABIVERSION]. */ 508 | + unsigned char word_size; /* maps to e_ident[EI_CLASS]. */ 509 | + unsigned char byte_order; /* maps to e_ident[EI_DATA]. */ 510 | + unsigned char reserved0; 511 | + unsigned char reserved1; 512 | + unsigned char offset[8]; 513 | + unsigned char size[8]; 514 | +} FatElf_External_Record; 515 | + 516 | +/* Values on disk are always littleendian, and align like Elf64. */ 517 | +typedef struct 518 | +{ 519 | + unsigned char magic[4]; /* always FATELF_MAGIC */ 520 | + unsigned char version[2]; /* latest is always FATELF_FORMAT_VERSION */ 521 | + unsigned char num_records; 522 | + unsigned char reserved0; 523 | +} FatElf_External_Hdr; 524 | + 525 | + 526 | #endif /* _ELF_EXTERNAL_H */ 527 | -------------------------------------------------------------------------------- /utils/fatelf-utils.c: -------------------------------------------------------------------------------- 1 | /** 2 | * FatELF; support multiple ELF binaries in one file. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | /* code shared between all FatELF utilities... */ 10 | 11 | #define FATELF_UTILS 1 12 | #include "fatelf-utils.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | const char *unlink_on_xfail = NULL; 19 | static uint8_t zerobuf[4096]; 20 | 21 | 22 | #ifndef APPID 23 | #define APPID fatelf 24 | #endif 25 | 26 | #ifndef APPREV 27 | #define APPREV "???" 28 | #endif 29 | 30 | #if (defined __GNUC__) 31 | # define VERSTR2(x) #x 32 | # define VERSTR(x) VERSTR2(x) 33 | # define COMPILERVER " " VERSTR(__GNUC__) "." VERSTR(__GNUC_MINOR__) "." VERSTR(__GNUC_PATCHLEVEL__) 34 | #elif (defined __SUNPRO_C) 35 | # define VERSTR2(x) #x 36 | # define VERSTR(x) VERSTR2(x) 37 | # define COMPILERVER " " VERSTR(__SUNPRO_C) 38 | #elif (defined __VERSION__) 39 | # define COMPILERVER " " __VERSION__ 40 | #else 41 | # define COMPILERVER "" 42 | #endif 43 | 44 | #ifndef __DATE__ 45 | #define __DATE__ "(Unknown build date)" 46 | #endif 47 | 48 | #ifndef __TIME__ 49 | #define __TIME__ "(Unknown build time)" 50 | #endif 51 | 52 | #ifndef COMPILER 53 | #if (defined __GNUC__) 54 | #define COMPILER "GCC" 55 | #elif (defined _MSC_VER) 56 | #define COMPILER "Visual Studio" 57 | #elif (defined __SUNPRO_C) 58 | #define COMPILER "Sun Studio" 59 | #else 60 | #error Please define your platform. 61 | #endif 62 | #endif 63 | 64 | // macro mess so we can turn APPID and APPREV into a string literal... 65 | #define MAKEBUILDVERSTRINGLITERAL2(id, rev) \ 66 | #id ", revision " rev ", built " __DATE__ " " __TIME__ \ 67 | ", by " COMPILER COMPILERVER 68 | 69 | #define MAKEBUILDVERSTRINGLITERAL(id, rev) MAKEBUILDVERSTRINGLITERAL2(id, rev) 70 | 71 | const char *fatelf_build_version = MAKEBUILDVERSTRINGLITERAL(APPID, APPREV); 72 | 73 | 74 | 75 | // Report an error to stderr and terminate immediately with exit(1). 76 | void xfail(const char *fmt, ...) 77 | { 78 | va_list ap; 79 | va_start(ap, fmt); 80 | vfprintf(stderr, fmt, ap); 81 | va_end(ap); 82 | fprintf(stderr, "\n"); 83 | fflush(stderr); 84 | 85 | if (unlink_on_xfail != NULL) 86 | unlink(unlink_on_xfail); // don't care if this fails. 87 | unlink_on_xfail = NULL; 88 | 89 | exit(1); 90 | } // xfail 91 | 92 | 93 | // Wrap malloc() with an xfail(), so this returns memory or calls exit(). 94 | // Memory is guaranteed to be initialized to zero. 95 | void *xmalloc(const size_t len) 96 | { 97 | void *retval = calloc(1, len); 98 | if (retval == NULL) 99 | xfail("Out of memory!"); 100 | return retval; 101 | } // xmalloc 102 | 103 | 104 | // Allocate a copy of (str), xfail() on allocation failure. 105 | char *xstrdup(const char *str) 106 | { 107 | char *retval = (char *) xmalloc(strlen(str) + 1); 108 | strcpy(retval, str); 109 | return retval; 110 | } // xstrdup 111 | 112 | 113 | // xfail() on error. 114 | int xopen(const char *fname, const int flags, const int perms) 115 | { 116 | const int retval = open(fname, flags, perms); 117 | if (retval == -1) 118 | xfail("Failed to open '%s': %s", fname, strerror(errno)); 119 | return retval; 120 | } // xopen 121 | 122 | 123 | // xfail() on error, handle EINTR. 124 | ssize_t xread(const char *fname, const int fd, void *buf, 125 | const size_t len, const int must_read) 126 | { 127 | ssize_t rc; 128 | while (((rc = read(fd,buf,len)) == -1) && (errno == EINTR)) { /* spin */ } 129 | if ( (rc == -1) || ((must_read) && (rc != len)) ) 130 | xfail("Failed to read '%s': %s", fname, strerror(errno)); 131 | return rc; 132 | } // xread 133 | 134 | 135 | // xfail() on error, handle EINTR. 136 | ssize_t xwrite(const char *fname, const int fd, 137 | const void *buf, const size_t len) 138 | { 139 | ssize_t rc; 140 | while (((rc = write(fd,buf,len)) == -1) && (errno == EINTR)) { /* spin */ } 141 | if (rc == -1) 142 | xfail("Failed to write '%s': %s", fname, strerror(errno)); 143 | return rc; 144 | } // xwrite 145 | 146 | // xfail() on error, handle EINTR. 147 | void xwrite_zeros(const char *fname, const int fd, size_t len) 148 | { 149 | while (len > 0) 150 | { 151 | const size_t count = (len < sizeof (zerobuf)) ? len : sizeof (zerobuf); 152 | xwrite(fname, fd, zerobuf, count); 153 | len -= count; 154 | } // while 155 | } // xwrite_zeros 156 | 157 | // xfail() on error, handle EINTR. 158 | void xclose(const char *fname, const int fd) 159 | { 160 | int rc; 161 | while ( ((rc = close(fd)) == -1) && (errno == EINTR) ) { /* spin. */ } 162 | if (rc == -1) 163 | xfail("Failed to close '%s': %s", fname, strerror(errno)); 164 | } // xopen 165 | 166 | 167 | // xfail() on error. 168 | void xlseek(const char *fname, const int fd, 169 | const off_t offset, const int whence) 170 | { 171 | if (lseek(fd, offset, whence) == -1) 172 | xfail("Failed to seek in '%s': %s", fname, strerror(errno)); 173 | } // xlseek 174 | 175 | 176 | uint64_t xget_file_size(const char *fname, const int fd) 177 | { 178 | struct stat statbuf; 179 | if (fstat(fd, &statbuf) == -1) 180 | xfail("Failed to fstat '%s': %s", fname, strerror(errno)); 181 | return (uint64_t) statbuf.st_size; 182 | } // xget_file_size 183 | 184 | 185 | static uint8_t copybuf[256 * 1024]; 186 | 187 | // xfail() on error. 188 | uint64_t xcopyfile(const char *in, const int infd, 189 | const char *out, const int outfd) 190 | { 191 | uint64_t retval = 0; 192 | ssize_t rc = 0; 193 | xlseek(in, infd, 0, SEEK_SET); 194 | while ( (rc = xread(in, infd, copybuf, sizeof (copybuf), 0)) > 0 ) 195 | { 196 | xwrite(out, outfd, copybuf, rc); 197 | retval += (uint64_t) rc; 198 | } // while 199 | 200 | return retval; 201 | } // xcopyfile 202 | 203 | 204 | static inline uint64_t minui64(const uint64_t a, const uint64_t b) 205 | { 206 | return (a < b) ? a : b; 207 | } // minui64 208 | 209 | 210 | void xcopyfile_range(const char *in, const int infd, 211 | const char *out, const int outfd, 212 | const uint64_t offset, const uint64_t size) 213 | { 214 | uint64_t remaining = size; 215 | xlseek(in, infd, (off_t) offset, SEEK_SET); 216 | while (remaining) 217 | { 218 | const size_t cpysize = minui64(remaining, sizeof (copybuf)); 219 | xread(in, infd, copybuf, cpysize, 1); 220 | xwrite(out, outfd, copybuf, cpysize); 221 | remaining -= (uint64_t) cpysize; 222 | } // while 223 | } // xcopyfile_range 224 | 225 | 226 | void xread_elf_header(const char *fname, const int fd, const uint64_t offset, 227 | FATELF_record *record) 228 | { 229 | const uint8_t magic[4] = { 0x7F, 0x45, 0x4C, 0x46 }; 230 | uint8_t buf[20]; // we only care about the first 20 bytes. 231 | xlseek(fname, fd, offset, SEEK_SET); 232 | xread(fname, fd, buf, sizeof (buf), 1); 233 | if (memcmp(magic, buf, sizeof (magic)) != 0) 234 | xfail("'%s' is not an ELF binary", fname); 235 | 236 | record->osabi = buf[7]; 237 | record->osabi_version = buf[8]; 238 | record->word_size = buf[4]; 239 | record->byte_order = buf[5]; 240 | record->reserved0 = 0; 241 | record->reserved1 = 0; 242 | record->offset = 0; 243 | record->size = 0; 244 | 245 | if ((record->word_size != FATELF_32BITS) && 246 | (record->word_size != FATELF_64BITS)) 247 | { 248 | xfail("Unexpected word size (%d) in '%s'", record->word_size, fname); 249 | } // if 250 | 251 | if (record->byte_order == FATELF_BIGENDIAN) 252 | record->machine = (((uint16_t)buf[18]) << 8) | (((uint16_t)buf[19])); 253 | else if (record->byte_order == FATELF_LITTLEENDIAN) 254 | record->machine = (((uint16_t)buf[19]) << 8) | (((uint16_t)buf[18])); 255 | else 256 | { 257 | xfail("Unexpected byte order (%d) in '%s'", 258 | (int) record->byte_order, fname); 259 | } // else 260 | } // xread_elf_header 261 | 262 | 263 | size_t fatelf_header_size(const int bincount) 264 | { 265 | return (sizeof (FATELF_header) + (sizeof (FATELF_record) * bincount)); 266 | } // fatelf_header_size 267 | 268 | 269 | // Write a uint8_t to a buffer. 270 | static inline uint8_t *putui8(uint8_t *ptr, const uint8_t val) 271 | { 272 | *(ptr++) = val; 273 | return ptr; 274 | } // putui8 275 | 276 | 277 | // Write a native uint16_t to a buffer in littleendian format. 278 | static inline uint8_t *putui16(uint8_t *ptr, const uint16_t val) 279 | { 280 | *(ptr++) = ((uint8_t) ((val >> 0) & 0xFF)); 281 | *(ptr++) = ((uint8_t) ((val >> 8) & 0xFF)); 282 | return ptr; 283 | } // putui16 284 | 285 | 286 | // Write a native uint32_t to a buffer in littleendian format. 287 | static inline uint8_t *putui32(uint8_t *ptr, const uint32_t val) 288 | { 289 | *(ptr++) = ((uint8_t) ((val >> 0) & 0xFF)); 290 | *(ptr++) = ((uint8_t) ((val >> 8) & 0xFF)); 291 | *(ptr++) = ((uint8_t) ((val >> 16) & 0xFF)); 292 | *(ptr++) = ((uint8_t) ((val >> 24) & 0xFF)); 293 | return ptr; 294 | } // putui32 295 | 296 | 297 | // Write a native uint64_t to a buffer in littleendian format. 298 | static inline uint8_t *putui64(uint8_t *ptr, const uint64_t val) 299 | { 300 | *(ptr++) = ((uint8_t) ((val >> 0) & 0xFF)); 301 | *(ptr++) = ((uint8_t) ((val >> 8) & 0xFF)); 302 | *(ptr++) = ((uint8_t) ((val >> 16) & 0xFF)); 303 | *(ptr++) = ((uint8_t) ((val >> 24) & 0xFF)); 304 | *(ptr++) = ((uint8_t) ((val >> 32) & 0xFF)); 305 | *(ptr++) = ((uint8_t) ((val >> 40) & 0xFF)); 306 | *(ptr++) = ((uint8_t) ((val >> 48) & 0xFF)); 307 | *(ptr++) = ((uint8_t) ((val >> 56) & 0xFF)); 308 | return ptr; 309 | } // putui64 310 | 311 | 312 | // Read a uint8_t from a buffer. 313 | static inline uint8_t *getui8(uint8_t *ptr, uint8_t *val) 314 | { 315 | *val = *ptr; 316 | return ptr + sizeof (*val); 317 | } // getui8 318 | 319 | 320 | // Read a littleendian uint16_t from a buffer in native format. 321 | static inline uint8_t *getui16(uint8_t *ptr, uint16_t *val) 322 | { 323 | *val = ( (((uint16_t) ptr[0]) << 0) | (((uint16_t) ptr[1]) << 8) ); 324 | return ptr + sizeof (*val); 325 | } // getui16 326 | 327 | 328 | // Read a littleendian uint32_t from a buffer in native format. 329 | static inline uint8_t *getui32(uint8_t *ptr, uint32_t *val) 330 | { 331 | *val = ( (((uint32_t) ptr[0]) << 0) | 332 | (((uint32_t) ptr[1]) << 8) | 333 | (((uint32_t) ptr[2]) << 16) | 334 | (((uint32_t) ptr[3]) << 24) ); 335 | return ptr + sizeof (*val); 336 | } // getui32 337 | 338 | 339 | // Read a littleendian uint64_t from a buffer in native format. 340 | static inline uint8_t *getui64(uint8_t *ptr, uint64_t *val) 341 | { 342 | *val = ( (((uint64_t) ptr[0]) << 0) | 343 | (((uint64_t) ptr[1]) << 8) | 344 | (((uint64_t) ptr[2]) << 16) | 345 | (((uint64_t) ptr[3]) << 24) | 346 | (((uint64_t) ptr[4]) << 32) | 347 | (((uint64_t) ptr[5]) << 40) | 348 | (((uint64_t) ptr[6]) << 48) | 349 | (((uint64_t) ptr[7]) << 56) ); 350 | return ptr + sizeof (*val); 351 | } // getui64 352 | 353 | 354 | void xwrite_fatelf_header(const char *fname, const int fd, 355 | const FATELF_header *header) 356 | { 357 | const size_t buflen = FATELF_DISK_FORMAT_SIZE(header->num_records); 358 | uint8_t *buf = (uint8_t *) xmalloc(buflen); 359 | uint8_t *ptr = buf; 360 | int i; 361 | 362 | ptr = putui32(ptr, header->magic); 363 | ptr = putui16(ptr, header->version); 364 | ptr = putui8(ptr, header->num_records); 365 | ptr = putui8(ptr, header->reserved0); 366 | 367 | for (i = 0; i < header->num_records; i++) 368 | { 369 | ptr = putui16(ptr, header->records[i].machine); 370 | ptr = putui8(ptr, header->records[i].osabi); 371 | ptr = putui8(ptr, header->records[i].osabi_version); 372 | ptr = putui8(ptr, header->records[i].word_size); 373 | ptr = putui8(ptr, header->records[i].byte_order); 374 | ptr = putui8(ptr, header->records[i].reserved0); 375 | ptr = putui8(ptr, header->records[i].reserved1); 376 | ptr = putui64(ptr, header->records[i].offset); 377 | ptr = putui64(ptr, header->records[i].size); 378 | } // for 379 | 380 | assert(ptr == (buf + buflen)); 381 | 382 | xlseek(fname, fd, 0, SEEK_SET); // jump to start of file again. 383 | xwrite(fname, fd, buf, buflen); 384 | 385 | free(buf); 386 | } // xwrite_fatelf_header 387 | 388 | // don't forget to free() the returned pointer! 389 | FATELF_header *xread_fatelf_header(const char *fname, const int fd) 390 | { 391 | FATELF_header *header = NULL; 392 | uint8_t buf[8]; 393 | uint8_t *fullbuf = NULL; 394 | uint8_t *ptr = buf; 395 | uint32_t magic = 0; 396 | uint16_t version = 0; 397 | uint8_t bincount = 0; 398 | uint8_t reserved0 = 0; 399 | size_t buflen = 0; 400 | int i = 0; 401 | 402 | xlseek(fname, fd, 0, SEEK_SET); // just in case. 403 | xread(fname, fd, buf, sizeof (buf), 1); 404 | ptr = getui32(ptr, &magic); 405 | ptr = getui16(ptr, &version); 406 | ptr = getui8(ptr, &bincount); 407 | ptr = getui8(ptr, &reserved0); 408 | 409 | if (magic != FATELF_MAGIC) 410 | xfail("'%s' is not a FatELF binary.", fname); 411 | else if (version != 1) 412 | xfail("'%s' uses an unknown FatELF version.", fname); 413 | 414 | buflen = FATELF_DISK_FORMAT_SIZE(bincount) - sizeof (buf); 415 | ptr = fullbuf = (uint8_t *) xmalloc(buflen); 416 | xread(fname, fd, fullbuf, buflen, 1); 417 | 418 | header = (FATELF_header *) xmalloc(fatelf_header_size(bincount)); 419 | header->magic = magic; 420 | header->version = version; 421 | header->num_records = bincount; 422 | header->reserved0 = reserved0; 423 | 424 | for (i = 0; i < bincount; i++) 425 | { 426 | ptr = getui16(ptr, &header->records[i].machine); 427 | ptr = getui8(ptr, &header->records[i].osabi); 428 | ptr = getui8(ptr, &header->records[i].osabi_version); 429 | ptr = getui8(ptr, &header->records[i].word_size); 430 | ptr = getui8(ptr, &header->records[i].byte_order); 431 | ptr = getui8(ptr, &header->records[i].reserved0); 432 | ptr = getui8(ptr, &header->records[i].reserved1); 433 | ptr = getui64(ptr, &header->records[i].offset); 434 | ptr = getui64(ptr, &header->records[i].size); 435 | } // for 436 | 437 | assert(ptr == (fullbuf + buflen)); 438 | 439 | free(fullbuf); 440 | return header; 441 | } // xread_fatelf_header 442 | 443 | 444 | uint64_t align_to_page(const uint64_t offset) 445 | { 446 | const size_t pagesize = 4096; // !!! FIXME: hardcoded pagesize. 447 | const size_t overflow = (offset % pagesize); 448 | return overflow ? (offset + (pagesize - overflow)) : offset; 449 | } // align_to_page 450 | 451 | 452 | // !!! FIXME: these names/descs aren't set in stone. 453 | // List from: http://www.sco.com/developers/gabi/latest/ch4.eheader.html 454 | static const fatelf_machine_info machines[] = 455 | { 456 | // MUST BE SORTED BY ID! 457 | { 0, "none", "No machine" }, 458 | { 1, "m32", "AT&T WE 32100" }, 459 | { 2, "sparc", "SPARC" }, 460 | { 3, "i386", "Intel 80386" }, 461 | { 4, "68k", "Motorola 68000" }, 462 | { 5, "88k", "Motorola 88000" }, 463 | { 7, "860", "Intel 80860" }, 464 | { 8, "mips", "MIPS I" }, 465 | { 9, "s370", "IBM System/370" }, 466 | { 10, "mips-rs3", "MIPS RS3000" }, 467 | { 15, "pa-risc", "Hewlett-Packard PA-RISC" }, 468 | { 17, "vpp500", "Fujitsu VPP500" }, 469 | { 18, "sparc32plus", "Enhanced instruction set SPARC" }, 470 | { 19, "960", "Intel 80960" }, 471 | { 20, "ppc", "PowerPC" }, 472 | { 21, "ppc64", "64-bit PowerPC" }, 473 | { 22, "s390", "IBM System/390" }, 474 | { 36, "v800", "NEC V800" }, 475 | { 37, "fr20", "Fujitsu FR20" }, 476 | { 38, "rh32", "TRW RH-32" }, 477 | { 39, "rce", "Motorola RCE" }, 478 | { 40, "arm", "Advanced RISC Machines ARM" }, 479 | { 41, "alpha", "Digital Alpha" }, 480 | { 42, "sh", "Hitachi SH" }, 481 | { 43, "sparcv9", "SPARC Version 9" }, 482 | { 44, "tricore", "Siemens Tricore embedded" }, 483 | { 45, "arc", "Argonaut RISC Core" }, 484 | { 46, "h8-300", "Hitachi H8/300" }, 485 | { 47, "h8-300h", "Hitachi H8/300H" }, 486 | { 48, "h8s", "Hitachi H8S" }, 487 | { 49, "h8-500", "Hitachi H8/500" }, 488 | { 50, "ia64", "Intel IA-64" }, 489 | { 51, "mipsx", "Stanford MIPS-X" }, 490 | { 52, "coldfire", "Motorola Coldfire" }, 491 | { 53, "m68hc12", "Motorola M68HC12" }, 492 | { 54, "mma", "Fujitsu MMA Multimedia Accelerator" }, 493 | { 55, "pcp", "Siemens PCP" }, 494 | { 56, "ncpu", "Sony nCPU embedded RISC" }, 495 | { 57, "ndr1", "Denso NDR1" }, 496 | { 58, "starcore", "Motorola Star*Core" }, 497 | { 59, "me16", "Toyota ME16" }, 498 | { 60, "st100", "STMicroelectronics ST100" }, 499 | { 61, "tinyj", "Advanced Logic Corp. TinyJ" }, 500 | { 62, "x86_64", "AMD x86-64" }, 501 | { 63, "pdsp", "Sony DSP" }, 502 | { 64, "pdp10", "Digital Equipment Corp. PDP-10" }, 503 | { 65, "pdp11", "Digital Equipment Corp. PDP-11" }, 504 | { 66, "fx66", "Siemens FX66" }, 505 | { 67, "st9plus", "STMicroelectronics ST9+" }, 506 | { 68, "st7", "STMicroelectronics ST7" }, 507 | { 69, "68hc16", "Motorola MC68HC16" }, 508 | { 70, "68hc11", "Motorola MC68HC11" }, 509 | { 70, "68hc11", "Motorola MC68HC11" }, 510 | { 71, "68hc08", "Motorola MC68HC08" }, 511 | { 72, "68hc05", "Motorola MC68HC05" }, 512 | { 73, "svx", "Silicon Graphics SVx" }, 513 | { 74, "st19", "STMicroelectronics ST19" }, 514 | { 75, "vax", "Digital VAX" }, 515 | { 76, "cris", "Axis Communications 32-bit embedded processor" }, 516 | { 77, "javelin", "Infineon Technologies 32-bit embedded processor" }, 517 | { 78, "firepath", "Element 14 64-bit DSP Processor" }, 518 | { 79, "zsp", "LSI Logic 16-bit DSP Processor" }, 519 | { 80, "mmix", "Donald Knuth's educational 64-bit processor" }, 520 | { 81, "huany", "Harvard University machine-independent object files" }, 521 | { 82, "prism", "SiTera Prism" }, 522 | { 83, "avr", "Atmel AVR" }, 523 | { 84, "fr30", "Fujitsu FR30" }, 524 | { 85, "d10v", "Mitsubishi D10V" }, 525 | { 86, "d30v", "Mitsubishi D30V" }, 526 | { 87, "v850", "NEC v850" }, 527 | { 88, "m32r", "Mitsubishi M32R" }, 528 | { 89, "mn10300", "Matsushita MN10300" }, 529 | { 90, "mn10200", "Matsushita MN10200" }, 530 | { 91, "pj", "picoJava" }, 531 | { 92, "openrisc", "OpenRISC" }, 532 | { 93, "arc_a5", "ARC Cores Tangent-A5" }, 533 | { 94, "xtensa", "Tensilica Xtensa" }, 534 | { 95, "videocore", "Alphamosaic VideoCore" }, 535 | { 96, "tmm_gpp", "Thompson Multimedia General Purpose Processor" }, 536 | { 97, "ns32k", "National Semiconductor 32000 series" }, 537 | { 98, "tpc", "Tenor Network TPC" }, 538 | { 99, "snp1k", "Trebia SNP 1000" }, 539 | { 100, "st200", "STMicroelectronics ST200" }, 540 | { 101, "ip2k", "Ubicom IP2xxx" }, 541 | { 102, "max", "MAX Processor" }, 542 | { 103, "cr", "National Semiconductor CompactRISC" }, 543 | { 104, "f2mc16", "Fujitsu F2MC16" }, 544 | { 105, "msp430", "Texas Instruments msp430" }, 545 | { 106, "blackfin", "Analog Devices Blackfin" }, 546 | { 107, "se_c33", "S1C33 Family of Seiko Epson processors" }, 547 | { 108, "sep", "Sharp embedded microprocessor" }, 548 | { 109, "arca", "Arca RISC Microprocessor" }, 549 | { 110, "unicore", "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University" }, 550 | { 0x9026, "alpha", "Digital Alpha" }, // linux headers use this. 551 | { 0x9080, "v850", "NEC v850" }, // old tools use this, apparently. 552 | { 0x9041, "m32r", "Mitsubishi M32R" }, // old tools use this, apparently. 553 | { 0xA390, "s390", "IBM System/390" }, // legacy value. 554 | { 0xBEEF, "mn10300", "Matsushita MN10300" }, // old tools. 555 | }; 556 | 557 | 558 | // !!! FIXME: these names/descs aren't set in stone. 559 | // List from: http://www.sco.com/developers/gabi/latest/ch4.eheader.html 560 | static const fatelf_osabi_info osabis[] = 561 | { 562 | // MUST BE SORTED BY ID! 563 | { 0, "sysv", "UNIX System V" }, 564 | { 1, "hpux", "Hewlett-Packard HP-UX" }, 565 | { 2, "netbsd", "NetBSD" }, 566 | { 3, "linux", "Linux" }, 567 | { 4, "hurd", "Hurd" }, 568 | { 5, "86open", "86Open common IA32" }, 569 | { 6, "solaris", "Sun Solaris" }, 570 | { 7, "aix", "AIX" }, 571 | { 8, "irix", "IRIX" }, 572 | { 9, "freebsd", "FreeBSD" }, 573 | { 10, "tru64", "Compaq TRU64 UNIX" }, 574 | { 11, "modesto", "Novell Modesto" }, 575 | { 12, "openbsd", "OpenBSD" }, 576 | { 13, "openvms", "OpenVMS" }, 577 | { 14, "nsk", "Hewlett-Packard Non-Stop Kernel" }, 578 | { 15, "aros", "Amiga Research OS" }, 579 | { 97, "armabi", "ARM" }, 580 | { 255, "standalone", "Standalone application" }, 581 | }; 582 | 583 | 584 | const fatelf_machine_info *get_machine_by_id(const uint16_t id) 585 | { 586 | int i; 587 | for (i = 0; i < (sizeof (machines) / sizeof (machines[0])); i++) 588 | { 589 | if (machines[i].id == id) 590 | return &machines[i]; 591 | else if (machines[i].id > id) 592 | break; // not found (sorted by id). 593 | } // for 594 | 595 | return NULL; 596 | } // get_machine_by_id 597 | 598 | 599 | const fatelf_machine_info *get_machine_by_name(const char *name) 600 | { 601 | int i; 602 | for (i = 0; i < (sizeof (machines) / sizeof (machines[0])); i++) 603 | { 604 | if (strcmp(machines[i].name, name) == 0) 605 | return &machines[i]; 606 | } // for 607 | 608 | return NULL; 609 | } // get_machine_by_name 610 | 611 | 612 | const fatelf_osabi_info *get_osabi_by_id(const uint8_t id) 613 | { 614 | int i; 615 | for (i = 0; i < (sizeof (osabis) / sizeof (osabis[0])); i++) 616 | { 617 | if (osabis[i].id == id) 618 | return &osabis[i]; 619 | else if (osabis[i].id > id) 620 | break; // not found (sorted by id). 621 | } // for 622 | 623 | return NULL; 624 | } // get_osabi_by_id 625 | 626 | 627 | const fatelf_osabi_info *get_osabi_by_name(const char *name) 628 | { 629 | int i; 630 | for (i = 0; i < (sizeof (osabis) / sizeof (osabis[0])); i++) 631 | { 632 | if (strcmp(osabis[i].name, name) == 0) 633 | return &osabis[i]; 634 | } // for 635 | 636 | return NULL; 637 | } // get_osabi_by_name 638 | 639 | 640 | static int parse_abi_version_string(const char *str) 641 | { 642 | long num = 0; 643 | char *endptr = NULL; 644 | const char *prefix = "osabiver"; 645 | const size_t prefix_len = 8; 646 | assert(strlen(prefix) == prefix_len); 647 | if (strncmp(str, prefix, prefix_len) != 0) 648 | return -1; 649 | 650 | str += prefix_len; 651 | num = strtol(str, &endptr, 0); 652 | return ( ((endptr == str) || (*endptr != '\0')) ? -1 : ((int) num) ); 653 | } // parse_abi_version_string 654 | 655 | 656 | static int xfind_fatelf_record_by_fields(const FATELF_header *header, 657 | const char *target) 658 | { 659 | char *buf = xstrdup(target); 660 | const fatelf_osabi_info *osabi = NULL; 661 | const fatelf_machine_info *machine = NULL; 662 | FATELF_record rec; 663 | int wants = 0; 664 | int abiver = 0; 665 | char *str = buf; 666 | char *ptr = buf; 667 | int retval = -1; 668 | int i = 0; 669 | 670 | memset(&rec, '\0', sizeof (rec)); 671 | 672 | while (1) 673 | { 674 | const char ch = *ptr; 675 | if ((ch == ':') || (ch == '\0')) 676 | { 677 | *ptr = '\0'; 678 | 679 | if (ptr == str) 680 | { 681 | // no-op for empty string. 682 | } // if 683 | else if ((strcmp(str,"be")==0) || (strcmp(str,"bigendian")==0)) 684 | { 685 | wants |= FATELF_WANT_BYTEORDER; 686 | rec.byte_order = FATELF_BIGENDIAN; 687 | } // if 688 | else if ((strcmp(str,"le")==0) || (strcmp(str,"littleendian")==0)) 689 | { 690 | wants |= FATELF_WANT_BYTEORDER; 691 | rec.byte_order = FATELF_LITTLEENDIAN; 692 | } // else if 693 | else if (strcmp(str,"32bit") == 0) 694 | { 695 | wants |= FATELF_WANT_WORDSIZE; 696 | rec.word_size = FATELF_32BITS; 697 | } // else if 698 | else if (strcmp(str,"64bit") == 0) 699 | { 700 | wants |= FATELF_WANT_WORDSIZE; 701 | rec.word_size = FATELF_64BITS; 702 | } // else if 703 | else if ((machine = get_machine_by_name(str)) != NULL) 704 | { 705 | wants |= FATELF_WANT_MACHINE; 706 | rec.machine = machine->id; 707 | } // else if 708 | else if ((osabi = get_osabi_by_name(str)) != NULL) 709 | { 710 | wants |= FATELF_WANT_OSABI; 711 | rec.osabi = osabi->id; 712 | } // else if 713 | else if ((abiver = parse_abi_version_string(str)) != -1) 714 | { 715 | wants |= FATELF_WANT_OSABIVER; 716 | rec.osabi_version = (uint8_t) abiver; 717 | } // else if 718 | else 719 | { 720 | xfail("Unknown target '%s'", str); 721 | } // else 722 | 723 | if (ch == '\0') 724 | break; // we're done. 725 | 726 | str = ptr + 1; 727 | } // if 728 | 729 | ptr++; 730 | } // while 731 | 732 | free(buf); 733 | 734 | for (i = 0; i < ((int) header->num_records); i++) 735 | { 736 | const FATELF_record *prec = &header->records[i]; 737 | if ((wants & FATELF_WANT_MACHINE) && (rec.machine != prec->machine)) 738 | continue; 739 | else if ((wants & FATELF_WANT_OSABI) && (rec.osabi != prec->osabi)) 740 | continue; 741 | else if ((wants & FATELF_WANT_OSABIVER) && (rec.osabi_version != prec->osabi_version)) 742 | continue; 743 | else if ((wants & FATELF_WANT_WORDSIZE) && (rec.word_size != prec->word_size)) 744 | continue; 745 | else if ((wants & FATELF_WANT_BYTEORDER) && (rec.byte_order != prec->byte_order)) 746 | continue; 747 | 748 | if (retval != -1) 749 | xfail("Ambiguous target '%s'", target); 750 | retval = i; 751 | } // for 752 | 753 | return retval; 754 | } // xfind_fatelf_record_by_fields 755 | 756 | 757 | int xfind_fatelf_record(const FATELF_header *header, const char *target) 758 | { 759 | if (strncmp(target, "record", 6) == 0) 760 | { 761 | char *endptr = NULL; 762 | const long num = strtol(target+6, &endptr, 0); 763 | if ((endptr != target+6) && (*endptr == '\0')) // a numeric index? 764 | { 765 | const long recs = (long) header->num_records; 766 | if ((num < 0) || (num > recs)) 767 | { 768 | xfail("No record #%ld in FatELF header (max %d)", 769 | num, (int) recs); 770 | } // if 771 | return (int) num; 772 | } // if 773 | } // if 774 | 775 | return xfind_fatelf_record_by_fields(header, target); 776 | } // xfind_fatelf_record 777 | 778 | 779 | int fatelf_record_matches(const FATELF_record *a, const FATELF_record *b) 780 | { 781 | return ( (a->machine == b->machine) && 782 | (a->osabi == b->osabi) && 783 | (a->osabi_version == b->osabi_version) && 784 | (a->word_size == b->word_size) && 785 | (a->byte_order == b->byte_order) ); 786 | } // fatelf_record_matches 787 | 788 | 789 | int find_furthest_record(const FATELF_header *header) 790 | { 791 | // there's nothing that says the records have to be in order, although 792 | // we probably _should_. Just in case, check them all. 793 | const int total = (int) header->num_records; 794 | uint64_t furthest = 0; 795 | int retval = -1; 796 | int i; 797 | 798 | for (i = 0; i < total; i++) 799 | { 800 | const FATELF_record *rec = &header->records[i]; 801 | const uint64_t edge = rec->offset + rec->size; 802 | if (edge > furthest) 803 | { 804 | retval = i; 805 | furthest = edge; 806 | } // if 807 | } // for 808 | 809 | return retval; 810 | } // find_furthest_record 811 | 812 | 813 | const char *fatelf_get_wordsize_string(const uint8_t wordsize) 814 | { 815 | if (wordsize == FATELF_32BITS) 816 | return "32"; 817 | else if (wordsize == FATELF_64BITS) 818 | return "64"; 819 | return "???"; 820 | } // fatelf_get_wordsize_string 821 | 822 | 823 | const char *fatelf_get_byteorder_name(const uint8_t byteorder) 824 | { 825 | if (byteorder == FATELF_LITTLEENDIAN) 826 | return "Littleendian"; 827 | else if (byteorder == FATELF_BIGENDIAN) 828 | return "Bigendian"; 829 | return "???"; 830 | } // get_byteorder_name 831 | 832 | 833 | const char *fatelf_get_byteorder_target_name(const uint8_t byteorder) 834 | { 835 | if (byteorder == FATELF_LITTLEENDIAN) 836 | return "le"; 837 | else if (byteorder == FATELF_BIGENDIAN) 838 | return "be"; 839 | return NULL; 840 | } // fatelf_get_byteorder_target_name 841 | 842 | 843 | const char *fatelf_get_wordsize_target_name(const uint8_t wordsize) 844 | { 845 | if (wordsize == FATELF_32BITS) 846 | return "32bits"; 847 | else if (wordsize == FATELF_64BITS) 848 | return "64bits"; 849 | return NULL; 850 | } // fatelf_get_wordsize_target_name 851 | 852 | 853 | 854 | const char *fatelf_get_target_name(const FATELF_record *rec, const int wants) 855 | { 856 | // !!! FIXME: this code is sort of stinky. 857 | static char buffer[128]; 858 | const fatelf_osabi_info *osabi = get_osabi_by_id(rec->osabi); 859 | const fatelf_machine_info *machine = get_machine_by_id(rec->machine); 860 | const char *order = fatelf_get_byteorder_target_name(rec->byte_order); 861 | const char *wordsize = fatelf_get_wordsize_target_name(rec->word_size); 862 | 863 | buffer[0] = '\0'; 864 | 865 | if ((wants & FATELF_WANT_MACHINE) && (machine)) 866 | { 867 | if (buffer[0]) 868 | strcat(buffer, ":"); 869 | strcat(buffer, machine->name); 870 | } // if 871 | 872 | if ((wants & FATELF_WANT_WORDSIZE) && (wordsize)) 873 | { 874 | if (buffer[0]) 875 | strcat(buffer, ":"); 876 | strcat(buffer, wordsize); 877 | } // if 878 | 879 | if ((wants & FATELF_WANT_BYTEORDER) && (order)) 880 | { 881 | if (buffer[0]) 882 | strcat(buffer, ":"); 883 | strcat(buffer, order); 884 | } // if 885 | 886 | if ((wants & FATELF_WANT_OSABI) && (osabi)) 887 | { 888 | if (buffer[0]) 889 | strcat(buffer, ":"); 890 | strcat(buffer, osabi->name); 891 | } // if 892 | 893 | if (wants & FATELF_WANT_OSABIVER) 894 | { 895 | char tmp[32]; 896 | if (buffer[0]) 897 | strcat(buffer, ":"); 898 | snprintf(tmp, sizeof (tmp), "osabiver%d", (int) rec->osabi_version); 899 | strcat(buffer, tmp); 900 | } // if 901 | 902 | return buffer; 903 | } // fatelf_get_target_name 904 | 905 | 906 | int xfind_junk(const char *fname, const int fd, const FATELF_header *header, 907 | uint64_t *offset, uint64_t *size) 908 | { 909 | const int furthest = find_furthest_record(header); 910 | 911 | if (furthest >= 0) // presumably, we failed elsewhere, but oh well. 912 | { 913 | const uint64_t fsize = xget_file_size(fname, fd); 914 | const FATELF_record *rec = &header->records[furthest]; 915 | const uint64_t edge = rec->offset + rec->size; 916 | if (fsize > edge) 917 | { 918 | *offset = edge; 919 | *size = fsize - edge; 920 | return 1; 921 | } // if 922 | } // if 923 | 924 | return 0; 925 | } // xfind_junk 926 | 927 | 928 | void xappend_junk(const char *fname, const int fd, 929 | const char *out, const int outfd, 930 | const FATELF_header *header) 931 | { 932 | uint64_t offset, size; 933 | if (xfind_junk(fname, fd, header, &offset, &size)) 934 | xcopyfile_range(fname, fd, out, outfd, offset, size); 935 | } // xappend_junk 936 | 937 | 938 | void xfatelf_init(int argc, const char **argv) 939 | { 940 | memset(zerobuf, '\0', sizeof (zerobuf)); // just in case. 941 | if ((argc >= 2) && (strcmp(argv[1], "--version") == 0)) 942 | { 943 | printf("%s\n", fatelf_build_version); 944 | exit(0); 945 | } // if 946 | } // xfatelf_init 947 | 948 | // end of fatelf-utils.c ... 949 | 950 | --------------------------------------------------------------------------------