Home | History | Annotate | Download | only in linkloader
      1 /*
      2  * Copyright 2011, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "ELFObject.h"
     18 
     19 #include "utils/serialize.h"
     20 #include "ELF.h"
     21 
     22 #include <llvm/ADT/OwningPtr.h>
     23 
     24 #include <fcntl.h>
     25 #include <stdlib.h>
     26 #include <sys/mman.h>
     27 #include <sys/stat.h>
     28 #include <sys/types.h>
     29 #include <map>
     30 #include <stdio.h>
     31 #include <stdarg.h>
     32 
     33 using namespace std;
     34 
     35 bool open_mmap_file(char const *filename,
     36                     int &fd,
     37                     unsigned char const *&image,
     38                     size_t &size);
     39 
     40 void close_mmap_file(int fd,
     41                      unsigned char const *image,
     42                      size_t size);
     43 
     44 void dump_and_run_file(unsigned char const *image, size_t size,
     45                        int argc, char **argv);
     46 
     47 int main(int argc, char **argv) {
     48   // Check arguments
     49   if (argc < 2) {
     50     llvm::errs() << "USAGE: " << argv[0] << " [ELFObjectFile] [ARGS]\n";
     51     exit(EXIT_FAILURE);
     52   }
     53 
     54   // Filename from argument
     55   char const *filename = argv[1];
     56 
     57   // Open the file
     58   int fd = -1;
     59   unsigned char const *image = NULL;
     60   size_t image_size = 0;
     61 
     62   if (!open_mmap_file(filename, fd, image, image_size)) {
     63     exit(EXIT_FAILURE);
     64   }
     65 
     66   // Dump and run the file
     67   dump_and_run_file(image, image_size, argc - 1, argv + 1);
     68 
     69   // Close the file
     70   close_mmap_file(fd, image, image_size);
     71 
     72   return EXIT_SUCCESS;
     73 }
     74 
     75 // FIXME: I don't like these stub as well.  However, before we implement
     76 // x86 64bit far jump stub, we have to ensure find_sym only returns
     77 // near address.
     78 
     79 int stub_printf(char const *fmt, ...) {
     80   va_list ap;
     81   va_start(ap, fmt);
     82   int result = vprintf(fmt, ap);
     83   va_end(ap);
     84   return result;
     85 }
     86 
     87 int stub_scanf(char const *fmt, ...) {
     88   va_list ap;
     89   va_start(ap, fmt);
     90   int result = vscanf(fmt, ap);
     91   va_end(ap);
     92   return result;
     93 }
     94 
     95 void stub_srand(unsigned int seed) {
     96   srand(seed);
     97 }
     98 
     99 int stub_rand() {
    100   return rand();
    101 }
    102 
    103 time_t stub_time(time_t *output) {
    104   return time(output);
    105 }
    106 
    107 void *find_sym(void *context, char const *name) {
    108   struct func_entry_t {
    109     char const *name;
    110     size_t name_len;
    111     void *addr;
    112   };
    113 
    114   static func_entry_t const tab[] = {
    115 #define DEF(NAME, ADDR) \
    116     { NAME, sizeof(NAME) - 1, (void *)(ADDR) },
    117 
    118     DEF("printf", stub_printf)
    119     DEF("scanf", stub_scanf)
    120     DEF("__isoc99_scanf", stub_scanf)
    121     DEF("rand", stub_rand)
    122     DEF("time", stub_time)
    123     DEF("srand", stub_srand)
    124 #undef DEF
    125   };
    126 
    127   static size_t const tab_size = sizeof(tab) / sizeof(func_entry_t);
    128 
    129   // Note: Since our table is small, we are using trivial O(n) searching
    130   // function.  For bigger table, it will be better to use binary
    131   // search or hash function.
    132   size_t name_len = strlen(name);
    133   for (size_t i = 0; i < tab_size; ++i) {
    134     if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
    135       return tab[i].addr;
    136     }
    137   }
    138 
    139   assert(0 && "Can't find symbol.");
    140   return 0;
    141 }
    142 
    143 template <unsigned Bitwidth, typename Archiver>
    144 void dump_and_run_object(Archiver &AR, int argc, char **argv) {
    145   llvm::OwningPtr<ELFObject<Bitwidth> > object(ELFObject<Bitwidth>::read(AR));
    146 
    147   if (!object) {
    148     llvm::errs() << "ERROR: Unable to load object\n";
    149   }
    150 
    151   object->print();
    152   out().flush();
    153 
    154   ELFSectionSymTab<Bitwidth> *symtab =
    155     static_cast<ELFSectionSymTab<Bitwidth> *>(
    156         object->getSectionByName(".symtab"));
    157 
    158   object->relocate(find_sym, 0);
    159   out() << "relocate finished!\n";
    160   out().flush();
    161 
    162   int machine = object->getHeader()->getMachine();
    163 
    164   void *main_addr = symtab->getByName("main")->getAddress(machine);
    165   out() << "main address: " << main_addr << "\n";
    166   out().flush();
    167 
    168   ((int (*)(int, char **))main_addr)(argc, argv);
    169   fflush(stdout);
    170 }
    171 
    172 template <typename Archiver>
    173 void dump_and_run_file_from_archive(bool is32bit, Archiver &AR,
    174                                     int argc, char **argv) {
    175   if (is32bit) {
    176     dump_and_run_object<32>(AR, argc, argv);
    177   } else {
    178     dump_and_run_object<64>(AR, argc, argv);
    179   }
    180 }
    181 
    182 void dump_and_run_file(unsigned char const *image, size_t size,
    183                        int argc, char **argv) {
    184   if (size < EI_NIDENT) {
    185     llvm::errs() << "ERROR: ELF identification corrupted.\n";
    186     return;
    187   }
    188 
    189   if (image[EI_DATA] != ELFDATA2LSB && image[EI_DATA] != ELFDATA2MSB) {
    190     llvm::errs() << "ERROR: Unknown endianness.\n";
    191     return;
    192   }
    193 
    194   if (image[EI_CLASS] != ELFCLASS32 && image[EI_CLASS] != ELFCLASS64) {
    195     llvm::errs() << "ERROR: Unknown machine class.\n";
    196     return;
    197   }
    198 
    199   bool isLittleEndian = (image[EI_DATA] == ELFDATA2LSB);
    200   bool is32bit = (image[EI_CLASS] == ELFCLASS32);
    201 
    202   if (isLittleEndian) {
    203     ArchiveReaderLE AR(image, size);
    204     dump_and_run_file_from_archive(is32bit, AR, argc, argv);
    205   } else {
    206     ArchiveReaderBE AR(image, size);
    207     dump_and_run_file_from_archive(is32bit, AR, argc, argv);
    208   }
    209 }
    210 
    211 bool open_mmap_file(char const *filename,
    212                     int &fd,
    213                     unsigned char const *&image,
    214                     size_t &size) {
    215   // Query the file status
    216   struct stat sb;
    217   if (stat(filename, &sb) != 0) {
    218     llvm::errs() << "ERROR: " << filename << " not found.\n";
    219     return false;
    220   }
    221 
    222   if (!S_ISREG(sb.st_mode)) {
    223     llvm::errs() << "ERROR: " << filename << " is not a regular file.\n";
    224     return false;
    225   }
    226 
    227   size = (size_t)sb.st_size;
    228 
    229   // Open the file in readonly mode
    230   fd = open(filename, O_RDONLY);
    231   if (fd < 0) {
    232     llvm::errs() << "ERROR: Unable to open " << filename << "\n";
    233     return false;
    234   }
    235 
    236   // Map the file image
    237   image = static_cast<unsigned char const *>(
    238     mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0));
    239 
    240   if (image == MAP_FAILED) {
    241     llvm::errs() << "ERROR: Unable to map " << filename << " to memory.\n";
    242     close(fd);
    243     return false;
    244   }
    245 
    246   return true;
    247 }
    248 
    249 void close_mmap_file(int fd,
    250                      unsigned char const *image,
    251                      size_t size) {
    252   if (image) {
    253     munmap((void *)image, size);
    254   }
    255 
    256   if (fd >= 0) {
    257     close(fd);
    258   }
    259 }
    260