The Pedigree Project  0.1
loader.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <malloc.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/klog.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 
32 #include <list>
33 #include <map>
34 #include <set>
35 #include <string>
36 
37 #define PACKED __attribute__((packed))
38 
39 // #define DEBUG_LIBLOAD
40 
41 #define _NO_ELF_CLASS
42 #include <Elf.h>
43 
44 #define STB_LOCAL 0
45 #define STB_GLOBAL 1
46 #define STB_WEAK 2
47 #define STB_LOPROC 13
48 #define STB_HIPROC 15
49 
50 typedef void (*entry_point_t)(const char *[], char **);
51 typedef void (*init_fini_func_t)();
52 
53 enum LookupPolicy
54 {
55  LocalFirst,
56  NotThisObject,
57  LocalLast
58 };
59 
60 typedef struct _object_meta
61 {
62  _object_meta()
63  : filename(), path(), entry(0), mapped_file(0), mapped_file_sz(0),
64  relocated(false), load_base(0), running(false), debug(false),
65  memory_regions(), phdrs(0), num_phdrs(0), shdrs(0), num_shdrs(0),
66  sh_symtab(0), sh_strtab(0), symtab(0), strtab(0), sh_shstrtab(0),
67  shstrtab(0), ph_dynamic(0), needed(0), dyn_symtab(0), dyn_strtab(0),
68  dyn_strtab_sz(0), rela(0), rel(0), rela_sz(0), rel_sz(0),
69  uses_rela(false), got(0), plt_rela(0), plt_rel(0), init_func(0),
70  fini_func(0), plt_sz(0), hash(0), hash_buckets(0), hash_chains(0),
71  preloads(), objects(), parent(0)
72  {
73  }
74 
75  std::string filename;
76  std::string path;
77  entry_point_t entry;
78 
79  const void *mapped_file;
80  size_t mapped_file_sz;
81 
82  bool relocated;
83  uintptr_t load_base;
84 
85  bool running;
86 
87  bool debug;
88 
89  std::list<std::pair<void *, size_t>> memory_regions;
90 
91  ElfProgramHeader_t *phdrs;
92  size_t num_phdrs;
93 
94  ElfSectionHeader_t *shdrs;
95  size_t num_shdrs;
96 
97  ElfSectionHeader_t *sh_symtab;
98  ElfSectionHeader_t *sh_strtab;
99 
100  const ElfSymbol_t *symtab;
101  const char *strtab;
102 
103  ElfSectionHeader_t *sh_shstrtab;
104  const char *shstrtab;
105 
106  ElfProgramHeader_t *ph_dynamic;
107 
108  std::list<std::string> needed;
109 
110  ElfSymbol_t *dyn_symtab;
111  const char *dyn_strtab;
112  size_t dyn_strtab_sz;
113 
114  ElfRela_t *rela;
115  ElfRel_t *rel;
116  size_t rela_sz;
117  size_t rel_sz;
118 
119  bool uses_rela;
120 
121  uintptr_t *got;
122 
123  ElfRela_t *plt_rela;
124  ElfRel_t *plt_rel;
125 
126  uintptr_t init_func;
127  uintptr_t fini_func;
128 
129  size_t plt_sz;
130 
131  const ElfHash_t *hash;
132  const Elf_Word *hash_buckets;
133  const Elf_Word *hash_chains;
134 
135  std::list<struct _object_meta *> preloads;
136  std::list<struct _object_meta *> objects;
137 
138  struct _object_meta *parent;
139 } object_meta_t;
140 
141 #define IS_NOT_PAGE_ALIGNED(x) (((x) & (getpagesize() - 1)) != 0)
142 
143 extern "C" void *pedigree_sys_request_mem(size_t len);
144 
145 bool loadObject(
146  const char *filename, object_meta_t *meta, bool envpath = false);
147 
148 bool loadSharedObjectHelper(
149  const char *filename, object_meta_t *parent, object_meta_t **out = NULL,
150  bool bRelocate = true);
151 
152 bool findSymbol(
153  const char *symbol, object_meta_t *meta, ElfSymbol_t &sym,
154  LookupPolicy policy = LocalFirst);
155 
156 bool lookupSymbol(
157  const char *symbol, object_meta_t *meta, ElfSymbol_t &sym, bool bWeak,
158  bool bGlobal = true);
159 
160 void doRelocation(object_meta_t *meta);
161 
162 uintptr_t doThisRelocation(ElfRel_t rel, object_meta_t *meta);
163 uintptr_t doThisRelocation(ElfRela_t rel, object_meta_t *meta);
164 
165 std::string symbolName(
166  const ElfSymbol_t &sym, object_meta_t *meta, bool bNoDynamic = false);
167 
168 std::string findObject(std::string name, bool envpath);
169 
170 extern "C" void *_libload_dlopen(const char *file, int mode);
171 extern "C" void *_libload_dlsym(void *handle, const char *name);
172 extern "C" int _libload_dlclose(void *handle);
173 
174 extern "C" uintptr_t _libload_resolve_symbol();
175 
176 object_meta_t *g_MainObject = 0;
177 
178 std::list<std::string> g_lSearchPaths;
179 
180 std::set<std::string> g_LoadedObjects;
181 
182 std::map<std::string, uintptr_t> g_LibLoadSymbols;
183 
184 extern char __elf_start;
185 extern char __start_bss;
186 extern char __end_bss;
187 
188 extern "C" void _init();
189 extern "C" void _fini();
190 extern "C" int _start(const char *argv[], const char *env[]);
191 
192 size_t elfhash(const char *name)
193 {
194  size_t h = 0, g = 0;
195  while (*name)
196  {
197  h = (h << 4) + *name++;
198  g = h & 0xF0000000;
199  h ^= g;
200  h ^= g >> 24;
201  }
202 
203  return h;
204 }
205 
206 extern char **environ;
207 
214 extern "C" int _libload_main(const char *argv[], const char *env[])
215 {
218 
219  // Get .bss loaded and ready early.
220  uintptr_t bssStart = reinterpret_cast<uintptr_t>(&__start_bss);
221  uintptr_t bssEnd = reinterpret_cast<uintptr_t>(&__end_bss);
222  mmap(
223  &__start_bss, bssEnd - bssStart, PROT_READ | PROT_WRITE,
224  MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_USERSVD, -1, 0);
225 
226  // Run .init stuff.
227  _init();
228 
229  int ret = _start(argv, env);
230 
231  // Run .fini stuff.
232  _fini();
233 
234  return ret;
235 }
236 
237 extern "C" int main(int argc, const char *argv[])
238 {
239  // Sanity check: do we actually have a program to load?
240  if (argc == 0)
241  {
242  return 0;
243  }
244 
245 #ifdef DEBUG_LIBLOAD
246  klog(LOG_INFO, "libload.so starting...");
247 #endif
248 
249  char *ld_libpath = getenv("LD_LIBRARY_PATH");
250  char *ld_preload = getenv("LD_PRELOAD");
251  char *ld_debug = getenv("LD_DEBUG");
252 
253  g_lSearchPaths.push_back(std::string("root»/libraries"));
254  g_lSearchPaths.push_back(std::string("."));
255 
256  // Prepare for libload hooks.
257  g_LibLoadSymbols.insert(std::pair<std::string, uintptr_t>(
258  "_libload_dlopen", (uintptr_t) _libload_dlopen));
259  g_LibLoadSymbols.insert(std::pair<std::string, uintptr_t>(
260  "_libload_dlsym", (uintptr_t) _libload_dlsym));
261  g_LibLoadSymbols.insert(std::pair<std::string, uintptr_t>(
262  "_libload_dlopen", (uintptr_t) _libload_dlclose));
263 
264  if (ld_libpath)
265  {
266  // Parse, write.
267  const char *entry;
268  while ((entry = strtok(ld_libpath, ":")))
269  {
270  g_lSearchPaths.push_back(std::string(entry));
271  }
272  }
273 
274  if (ld_debug)
275  {
276  fprintf(stderr, "libload.so: search path is\n");
277  for (std::list<std::string>::iterator it = g_lSearchPaths.begin();
278  it != g_lSearchPaths.end(); ++it)
279  {
280  printf(" -> %s\n", it->c_str());
281  }
282  }
283 
284 #ifdef DEBUG_LIBLOAD
285  klog(LOG_INFO, "libload.so loading main object");
286 #endif
287 
288  // Ungodly hack.
289  if (!strcmp(argv[0], "sh") || !strcmp(argv[0], "/bin/sh"))
290  {
291  // Get user's shell.
292  argv[0] = getenv("SHELL");
293  if (!argv[0])
294  {
295  // Assume bash.
296  klog(
297  LOG_WARNING,
298  "libload: $SHELL is undefined and /bin/sh was requested");
299  argv[0] = "bash";
300  }
301  }
302 
303 #ifdef DEBUG_LIBLOAD
304  klog(LOG_INFO, "libload.so main object is %s", argv[0]);
305 #endif
306 
307  // Load the main object passed on the command line.
308  object_meta_t *meta = g_MainObject = new object_meta_t;
309  meta->debug = false;
310  meta->running = false;
311  if (!loadObject(argv[0], meta, true))
312  {
313  delete meta;
314  return ENOEXEC;
315  }
316 
317  g_LoadedObjects.insert(meta->filename);
318 
319 #ifdef DEBUG_LIBLOAD
320  klog(LOG_INFO, "libload.so loading preload, if one exists");
321 #endif
322 
323  // Preload?
324  if (ld_preload)
325  {
326  object_meta_t *preload = new object_meta_t;
327  if (!loadObject(ld_preload, preload))
328  {
329  printf("Loading preload '%s' failed.\n", ld_preload);
330  }
331  else
332  {
333  preload->parent = meta;
334  meta->preloads.push_back(preload);
335 
336  g_LoadedObjects.insert(preload->filename);
337  }
338  }
339 
340 #ifdef DEBUG_LIBLOAD
341  klog(LOG_INFO, "libload.so loading dependencies");
342 #endif
343 
344  // Any libraries to load?
345  if (meta->needed.size())
346  {
347  for (std::list<std::string>::iterator it = meta->needed.begin();
348  it != meta->needed.end(); ++it)
349  {
350  if (g_LoadedObjects.find(*it) == g_LoadedObjects.end())
351  loadSharedObjectHelper(it->c_str(), meta, NULL, false);
352  }
353  }
354 
355 #ifdef DEBUG_LIBLOAD
356  klog(LOG_INFO, "libload.so relocating dependencies");
357 #endif
358 
359  // Relocate preloads.
360  for (std::list<struct _object_meta *>::iterator it = meta->preloads.begin();
361  it != meta->preloads.end(); ++it)
362  {
363  doRelocation(*it);
364  }
365 
366  // Relocate all other loaded objects.
367  for (std::list<struct _object_meta *>::iterator it = meta->objects.begin();
368  it != meta->objects.end(); ++it)
369  {
370  doRelocation(*it);
371  }
372 
373 #ifdef DEBUG_LIBLOAD
374  klog(LOG_INFO, "libload.so relocating main object");
375 #endif
376 
377  // Do initial relocation of the binary (non-GOT entries)
378  doRelocation(meta);
379 
380  // All done - run the program!
381  meta->running = true;
382 
383  // Run init functions in loaded objects.
384  for (std::list<struct _object_meta *>::iterator it = meta->objects.begin();
385  it != meta->objects.end(); ++it)
386  {
387  if ((*it)->init_func)
388  {
389 #ifdef DEBUG_LIBLOAD
390  klog(
391  LOG_INFO, "libload.so running init_func for %s",
392  (*it)->filename.c_str());
393 #endif
394  init_fini_func_t init = (init_fini_func_t)(*it)->init_func;
395  init();
396  }
397  }
398 
399  // Run init function, if one exists.
400  if (meta->init_func)
401  {
402  init_fini_func_t init = (init_fini_func_t) meta->init_func;
403 #ifdef DEBUG_LIBLOAD
404  klog(
405  LOG_INFO, "libload.so running init_func for %s",
406  meta->filename.c_str());
407 #endif
408  init();
409  }
410 
411  // Register fini functions with atexit for loaded objects.
412  for (std::list<struct _object_meta *>::iterator it = meta->objects.begin();
413  it != meta->objects.end(); ++it)
414  {
415  if ((*it)->fini_func)
416  {
417  init_fini_func_t fini = (init_fini_func_t)(*it)->fini_func;
418  atexit(fini);
419  }
420  }
421 
422  // Register fini function for this object with atexit.
423  if (meta->fini_func)
424  {
425  init_fini_func_t fini = (init_fini_func_t) meta->fini_func;
426  atexit(fini);
427  }
428 
429 // argv[0] is passed to us by the kernel and holds the path to the binary
430 // we need to load. argv[1:] is the original argv.
431 #ifdef DEBUG_LIBLOAD
432  klog(LOG_INFO, "libload.so running entry point");
433 #endif
434  meta->entry(&argv[1], environ);
435 
436  return 0;
437 }
438 
439 std::string findObject(std::string name, bool envpath)
440 {
441  std::list<std::string>::iterator it = g_lSearchPaths.begin();
442  if (it != g_lSearchPaths.end())
443  {
444  std::string fixed_path;
445 
446  // Don't do fixup for an absolute path.
447  if ((name[0] == '.') || (name[0] == '/') ||
448  (name.find("»") != std::string::npos))
449  fixed_path = name;
450  else
451  {
452  fixed_path = *it;
453  fixed_path += "/";
454  fixed_path += name;
455  }
456 
457  do
458  {
459 #ifdef SUPERDEBUG
460  klog(LOG_INFO, "Trying %s", fixed_path.c_str());
461 #endif
462 
463  struct stat st;
464  int l = stat(fixed_path.c_str(), &st);
465  if ((l == 0) && S_ISREG(st.st_mode))
466  {
467  return fixed_path;
468  }
469 
470  fixed_path = *it;
471  fixed_path += "/";
472  fixed_path += name;
473  } while (++it != g_lSearchPaths.end());
474  }
475 
476  if (envpath)
477  {
478  // Check $PATH for the file.
479  char *path = getenv("PATH");
480 
481  if (path)
482  {
483  // Parse, write.
484  const char *entry = strtok(path, ":");
485  if (entry)
486  {
487  do
488  {
489  g_lSearchPaths.push_back(std::string(entry));
490 
492  std::string fixed_path(entry);
493  fixed_path += "/";
494  fixed_path += name;
495 
496 #ifdef SUPERDEBUG
497  klog(LOG_INFO, "Trying %s", fixed_path.c_str());
498 #endif
499 
500  std::string result = findObject(fixed_path, false);
501 
502  if (result.compare("<not found>") != 0)
503  return result;
504 
505  // Remove from the search paths - wasn't found.
506  g_lSearchPaths.pop_back();
507  } while ((entry = strtok(NULL, ":")));
508  }
509  }
510  }
511 
512  return std::string("<not found>");
513 }
514 
515 bool loadSharedObjectHelper(
516  const char *filename, object_meta_t *parent, object_meta_t **out,
517  bool bRelocate)
518 {
519  object_meta_t *object = new object_meta_t;
520  bool bSuccess = true;
521  if (!loadObject(filename, object))
522  {
523  printf("Loading '%s' failed.\n", filename);
524  bSuccess = false;
525  }
526  else
527  {
528  object->parent = parent;
529  parent->objects.push_back(object);
530  g_LoadedObjects.insert(object->filename);
531 
532  if (object->needed.size())
533  {
534  for (std::list<std::string>::iterator it = object->needed.begin();
535  it != object->needed.end(); ++it)
536  {
537  if (g_LoadedObjects.find(*it) == g_LoadedObjects.end())
538  {
539  object_meta_t *child = 0;
540  bSuccess = loadSharedObjectHelper(
541  it->c_str(), parent, &child, bRelocate);
542  }
543  }
544  }
545  }
546 
547  if (out)
548  {
549  *out = object;
550  }
551 
552  // Relocate object - now loaded.
553  if (bRelocate)
554  {
555  doRelocation(object);
556  }
557 
558  return bSuccess;
559 }
560 
561 bool loadObject(const char *filename, object_meta_t *meta, bool envpath)
562 {
563  meta->filename = filename;
564  meta->path = findObject(meta->filename, envpath);
565 #ifdef DEBUG_LIBLOAD
566  klog(LOG_INFO, "libload.so loading %s", filename);
567 #endif
568 
569  // Okay, let's open up the file for reading...
570  int fd = open(meta->path.c_str(), O_RDONLY);
571  if (fd < 0)
572  {
573  fprintf(
574  stderr, "libload.so: couldn't load object '%s' (%s) (%s)\n",
575  filename, meta->path.c_str(), strerror(errno));
576  return false;
577  }
578 
579  // Check header.
580  ElfHeader_t header;
581  int n = read(fd, &header, sizeof(header));
582  if (n < 0)
583  {
584 #ifdef DEBUG_LIBLOAD
585  fprintf(
586  stderr, "libload.so: couldn't read file header (%s)\n",
587  strerror(errno));
588 #else
589  klog(
590  LOG_INFO, "libload.so: couldn't read file header (%s)",
591  strerror(errno));
592 #endif
593  close(fd);
594  return false;
595  }
596  else if (n != sizeof(header))
597  {
598 #ifdef DEBUG_LIBLOAD
599  fprintf(stderr, "libload.so: read was not the correct size\n");
600 #else
601  klog(LOG_INFO, "libload.so: read was not the correct size");
602 #endif
603  close(fd);
604  errno = ENOEXEC;
605  return false;
606  }
607 
608  if (header.ident[1] != 'E' || header.ident[2] != 'L' ||
609  header.ident[3] != 'F' || header.ident[0] != 127)
610  {
611 #ifdef DEBUG_LIBLOAD
612  fprintf(stderr, "libload.so: bad ELF magic\n");
613 #else
614  klog(LOG_INFO, "libload.so: bad ELF magic");
615 #endif
616  close(fd);
617  errno = ENOEXEC;
618  return false;
619  }
620 
621  // Fairly confident we have an ELF binary now. Valid class?
622  if (!(header.ident[4] == 1 || header.ident[4] == 2))
623  {
624 #ifdef DEBUG_LIBLOAD
625  fprintf(stderr, "libload.so: not a valid ELF class\n");
626 #else
627  klog(LOG_INFO, "libload.so: not a valid ELF class");
628 #endif
629  close(fd);
630  errno = ENOEXEC;
631  return false;
632  }
633 
634  meta->entry = (entry_point_t) header.entry;
635 
636  // Grab the size of the file - we'll mmap the entire thing, and pull out
637  // what we want.
638  struct stat st;
639  fstat(fd, &st);
640 
641  meta->mapped_file_sz = st.st_size;
642 
643  const char *pBuffer = (const char *) mmap(
644  0, meta->mapped_file_sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
645  if (pBuffer == MAP_FAILED)
646  {
647 #ifdef DEBUG_LIBLOAD
648  fprintf(stderr, "libload.so: could not mmap binary\n");
649 #else
650  klog(LOG_INFO, "libload.so: could not mmap binary");
651 #endif
652  close(fd);
653  errno = ENOEXEC;
654  return false;
655  }
656  meta->mapped_file = pBuffer;
657 
658  meta->phdrs = const_cast<ElfProgramHeader_t *>(
659  reinterpret_cast<const ElfProgramHeader_t *>(&pBuffer[header.phoff]));
660  meta->num_phdrs = header.phnum;
661  meta->shdrs = const_cast<ElfSectionHeader_t *>(
662  reinterpret_cast<const ElfSectionHeader_t *>(&pBuffer[header.shoff]));
663  meta->num_shdrs = header.shnum;
664 
665  if (header.type == ET_REL)
666  {
667  meta->relocated = true;
668  }
669  else if (header.type == ET_EXEC || header.type == ET_DYN)
670  {
671  // First PT_LOAD program header zero?
672  if (header.phnum)
673  {
674  for (size_t i = 0; i < header.phnum; ++i)
675  {
676  if (meta->phdrs[i].type != PT_LOAD)
677  continue;
678 
679  meta->relocated =
680  (meta->phdrs[i].vaddr & ~(getpagesize() - 1)) == 0;
681  break;
682  }
683  }
684  }
685 
686  meta->sh_shstrtab = &meta->shdrs[header.shstrndx];
687  meta->shstrtab = &pBuffer[meta->sh_shstrtab->offset];
688 
689  // Find the symbol and string tables (these are not the dynamic ones).
690  meta->sh_symtab = 0;
691  meta->sh_strtab = 0;
692  for (int i = 0; i < header.shnum; i++)
693  {
694  const char *name = meta->shstrtab + meta->shdrs[i].name;
695  if (meta->shdrs[i].type == SHT_SYMTAB && !strcmp(name, ".symtab"))
696  {
697  meta->sh_symtab = &meta->shdrs[i];
698  }
699  else if (meta->shdrs[i].type == SHT_STRTAB && !strcmp(name, ".strtab"))
700  {
701  meta->sh_strtab = &meta->shdrs[i];
702  }
703  }
704 
705  meta->symtab = 0;
706  meta->strtab = 0;
707 
708  if (meta->sh_symtab != 0)
709  {
710  meta->symtab = reinterpret_cast<const ElfSymbol_t *>(
711  &pBuffer[meta->sh_symtab->offset]);
712  }
713 
714  if (meta->sh_strtab != 0)
715  {
716  meta->strtab = &pBuffer[meta->sh_strtab->offset];
717  }
718 
719  // Load program headers.
720  meta->load_base = 0;
721  if (header.phnum)
722  {
723  if (meta->relocated)
724  {
725  // Reserve space for the full loaded virtual address space of the
726  // process.
727  meta->load_base = meta->phdrs[0].vaddr & ~(getpagesize() - 1);
728  uintptr_t finalAddress = 0;
729  for (size_t i = 0; i < header.phnum; ++i)
730  {
731  uintptr_t endAddr = meta->phdrs[i].vaddr + meta->phdrs[i].memsz;
732  finalAddress = std::max(finalAddress, endAddr);
733  }
734  size_t mapSize = finalAddress - meta->load_base;
735  if (mapSize & (getpagesize() - 1))
736  {
737  mapSize = (mapSize + getpagesize()) & ~(getpagesize() - 1);
738  }
739 
740  void *p = pedigree_sys_request_mem(mapSize);
741  if (!p)
742  {
743  munmap(const_cast<char *>(pBuffer), meta->mapped_file_sz);
744  errno = ENOEXEC;
745  klog(
746  LOG_INFO,
747  "libload.so: couldn't get memory for relocated object");
748  return false;
749  }
750 
751  meta->load_base = (uintptr_t) p;
752  if (meta->load_base & (getpagesize() - 1))
753  {
754  meta->load_base =
755  (meta->load_base + getpagesize()) & ~(getpagesize() - 1);
756  }
757 
758  // Patch up section headers, quickly.
759  for (size_t shdx = 0; shdx < header.shnum; ++shdx)
760  {
761  meta->shdrs[shdx].addr += meta->load_base;
762  }
763  }
764 
765  // NEEDED libraries are stored as offsets into the dynamic string table.
766  std::list<uintptr_t> tmp_needed;
767 
768  for (size_t i = 0; i < header.phnum; i++)
769  {
770  if (meta->phdrs[i].type == PT_DYNAMIC)
771  {
772  meta->ph_dynamic = &meta->phdrs[i];
773  if (meta->relocated)
774  {
775  meta->ph_dynamic->vaddr += meta->load_base;
776  }
777 
778  const ElfDyn_t *dyn =
779  (const ElfDyn_t *) &pBuffer[meta->phdrs[i].offset];
780 
781  while (dyn->tag != DT_NULL)
782  {
783  switch (dyn->tag)
784  {
785  case DT_NEEDED:
786  tmp_needed.push_back(dyn->un.ptr);
787  break;
788  case DT_SYMTAB:
789  meta->dyn_symtab = (ElfSymbol_t *) dyn->un.ptr;
790  break;
791  case DT_STRTAB:
792  meta->dyn_strtab = (const char *) dyn->un.ptr;
793  break;
794  case DT_STRSZ:
795  meta->dyn_strtab_sz = dyn->un.val;
796  break;
797  case DT_RELA:
798  meta->rela = (ElfRela_t *) dyn->un.ptr;
799  break;
800  case DT_REL:
801  meta->rel = (ElfRel_t *) dyn->un.ptr;
802  break;
803  case DT_RELASZ:
804  meta->rela_sz = dyn->un.val;
805  break;
806  case DT_RELSZ:
807  meta->rel_sz = dyn->un.val;
808  break;
809  case DT_PLTGOT:
810  meta->got = (uintptr_t *) dyn->un.ptr;
811  break;
812  case DT_JMPREL:
813  if (meta->uses_rela)
814  {
815  meta->plt_rela = (ElfRela_t *) dyn->un.ptr;
816  }
817  else
818  {
819  meta->plt_rel = (ElfRel_t *) dyn->un.ptr;
820  }
821  break;
822  case DT_PLTREL:
823  meta->uses_rela = dyn->un.val == DT_RELA;
824  break;
825  case DT_PLTRELSZ:
826  meta->plt_sz = dyn->un.val;
827  break;
828  case DT_INIT:
829  meta->init_func = dyn->un.val;
830  break;
831  case DT_FINI:
832  meta->fini_func = dyn->un.val;
833  break;
834  }
835  dyn++;
836  }
837  }
838  else if (meta->phdrs[i].type == PT_LOAD)
839  {
840  if (meta->relocated)
841  {
842  meta->phdrs[i].vaddr += meta->load_base;
843  }
844 
845  uintptr_t phdr_base = meta->phdrs[i].vaddr;
846 
847  size_t pagesz = getpagesize();
848 
849  size_t base_addend = phdr_base & (pagesz - 1);
850  phdr_base &= ~(pagesz - 1);
851 
852  size_t offset = 0;
853  if (meta->phdrs[i].offset)
854  {
855  offset = meta->phdrs[i].offset - base_addend;
856  }
857 
858  size_t mapsz = base_addend + meta->phdrs[i].filesz;
859 
860  // Already mapped?
861  if ((msync((void *) phdr_base, mapsz, MS_SYNC) != 0) &&
862  (errno == ENOMEM))
863  {
864  int mapflags = MAP_FIXED | MAP_PRIVATE;
865  if (meta->relocated)
866  {
867  mapflags |= MAP_USERSVD;
868  }
869 
870  int map_fd = fd;
871  if ((meta->phdrs[i].flags & PF_W) == 0)
872  {
873  // If the program header is read-only, we can quite
874  // happily share the mapping and reduce memory
875  // usage across the system.
876  mapflags &= ~(MAP_PRIVATE);
877  }
878 
879  // Zero out additional space.
880  if (meta->phdrs[i].memsz > meta->phdrs[i].filesz)
881  {
882  uintptr_t vaddr_start =
883  meta->phdrs[i].vaddr + meta->phdrs[i].filesz;
884  uintptr_t vaddr_end =
885  meta->phdrs[i].vaddr + meta->phdrs[i].memsz;
886  if ((vaddr_start & ~(getpagesize() - 1)) !=
887  (vaddr_end & ~(getpagesize() - 1)))
888  {
889  // Not the same page, won't be mapped in with the
890  // rest of the program header. Map the rest as an
891  // anonymous mapping.
892  vaddr_start += getpagesize();
893  vaddr_start &= ~(getpagesize() - 1);
894  size_t totalLength = vaddr_end - vaddr_start;
895  if (!totalLength)
896  totalLength = getpagesize();
897  void *p = mmap(
898  (void *) vaddr_start, totalLength,
899  PROT_READ | PROT_WRITE, mapflags | MAP_ANON, 0,
900  0);
901  if (p == MAP_FAILED)
902  {
904  klog(
905  LOG_INFO, "libload.so: mmap failed for "
906  "program header (anonymous "
907  "section)");
908  errno = ENOEXEC;
909  return false;
910  }
911  meta->memory_regions.push_back(
912  std::pair<void *, size_t>(p, totalLength));
913  }
914 #ifdef DEBUG_LIBLOAD
915  else
916  klog(
917  LOG_INFO,
918  "libload.so: not mapping filesz section at %p",
919  vaddr_start);
920 #endif
921  }
922 
923  void *p = mmap(
924  (void *) phdr_base, mapsz, PROT_READ | PROT_WRITE,
925  mapflags, map_fd, map_fd ? offset : 0);
926  if (p == MAP_FAILED)
927  {
929  errno = ENOEXEC;
930  klog(
931  LOG_INFO,
932  "libload.so: mmap failed for program header");
933  return false;
934  }
935 
936  meta->memory_regions.push_back(
937  std::pair<void *, size_t>(p, mapsz));
938  }
939  }
940  }
941 
942  if (meta->relocated)
943  {
944  uintptr_t base_vaddr = meta->load_base;
945 
946  // Patch up references.
947  if (meta->dyn_strtab)
948  meta->dyn_strtab += base_vaddr;
949  if (meta->dyn_symtab)
950  meta->dyn_symtab =
951  (ElfSymbol_t
952  *) (((uintptr_t) meta->dyn_symtab) + base_vaddr);
953  if (meta->got)
954  meta->got =
955  (uintptr_t *) (((uintptr_t) meta->got) + base_vaddr);
956  if (meta->rela)
957  meta->rela =
958  (ElfRela_t *) (((uintptr_t) meta->rela) + base_vaddr);
959  if (meta->rel)
960  meta->rel = (ElfRel_t *) (((uintptr_t) meta->rel) + base_vaddr);
961  if (meta->plt_rela)
962  meta->plt_rela =
963  (ElfRela_t *) (((uintptr_t) meta->plt_rela) + base_vaddr);
964  if (meta->plt_rel)
965  meta->plt_rel =
966  (ElfRel_t *) (((uintptr_t) meta->plt_rel) + base_vaddr);
967  if (meta->init_func)
968  meta->init_func += base_vaddr;
969  if (meta->fini_func)
970  meta->fini_func += base_vaddr;
971  }
972 
973  if (meta->dyn_strtab)
974  {
975  for (std::list<uintptr_t>::iterator it = tmp_needed.begin();
976  it != tmp_needed.end(); ++it)
977  {
978  std::string s(meta->dyn_strtab + *it);
979  meta->needed.push_back(s);
980  }
981  }
982  }
983  else
984  {
985  meta->phdrs = 0;
986  }
987 
988  // Do another pass over section headers to try and get the hash table.
989  meta->hash = 0;
990  meta->hash_buckets = 0;
991  meta->hash_chains = 0;
992  for (size_t i = 0; i < header.shnum; i++)
993  {
994  if (meta->shdrs[i].type == SHT_HASH)
995  {
996  uintptr_t vaddr = meta->shdrs[meta->shdrs[i].link].addr;
997  if (((uintptr_t) meta->dyn_symtab) == vaddr)
998  {
999  meta->hash =
1000  (const ElfHash_t *) &pBuffer[meta->shdrs[i].offset];
1001  meta->hash_buckets =
1002  (const Elf_Word
1003  *) &pBuffer[meta->shdrs[i].offset + sizeof(ElfHash_t)];
1004  meta->hash_chains = (const Elf_Word *) &pBuffer
1005  [meta->shdrs[i].offset + sizeof(ElfHash_t) +
1006  (sizeof(Elf_Word) * meta->hash->nbucket)];
1007  }
1008  }
1009  }
1010 
1011  // Patch up the GOT so we can start resolving symbols when needed.
1012  if (meta->got)
1013  {
1014  meta->got[1] = (uintptr_t) meta;
1015  meta->got[2] = (uintptr_t) _libload_resolve_symbol;
1016  }
1017 
1018  // mmap complete - don't need the file descriptors open any longer.
1019  close(fd);
1020 
1021  return true;
1022 }
1023 
1024 bool lookupSymbol(
1025  const char *symbol, object_meta_t *meta, ElfSymbol_t &sym, bool bWeak,
1026  bool bGlobal)
1027 {
1028  if (!meta)
1029  {
1030  return false;
1031  }
1032 
1033  // Allow preloads to override the main object symbol table, as well as any
1034  // others.
1035  for (std::list<object_meta_t *>::iterator it = meta->preloads.begin();
1036  it != meta->preloads.end(); ++it)
1037  {
1038  if (lookupSymbol(symbol, *it, sym, false))
1039  return true;
1040  }
1041 
1042  std::string sname(symbol);
1043 
1044  size_t hash = elfhash(symbol);
1045  size_t y = meta->hash_buckets[hash % meta->hash->nbucket];
1046  if (y > meta->hash->nchain)
1047  {
1048  return false;
1049  }
1050 
1051  // Try a local lookup first.
1052  do
1053  {
1054  sym = meta->dyn_symtab[y];
1055  if (symbolName(sym, meta) == sname)
1056  {
1057  if (ST_BIND(sym.info) == STB_LOCAL)
1058  {
1059  if (sym.shndx)
1060  {
1061  break;
1062  }
1063  }
1064  if (bWeak)
1065  {
1066  if (ST_BIND(sym.info) == STB_WEAK)
1067  {
1068  // sym.value = ~0UL;
1069  break;
1070  }
1071  }
1072  }
1073  y = meta->hash_chains[y];
1074  } while (y != 0);
1075 
1076  // No local symbols found - try a global lookup.
1077  if ((bGlobal) && (y == 0))
1078  {
1079  y = meta->hash_buckets[hash % meta->hash->nbucket];
1080  do
1081  {
1082  sym = meta->dyn_symtab[y];
1083  if (symbolName(sym, meta) == sname)
1084  {
1085  if (ST_BIND(sym.info) == STB_GLOBAL)
1086  {
1087  if (sym.shndx)
1088  {
1089  break;
1090  }
1091  }
1092  }
1093  y = meta->hash_chains[y];
1094  } while (y != 0);
1095  }
1096 
1097  if (y != 0)
1098  {
1099  // Patch up the value.
1100  if (ST_TYPE(sym.info) < 3)
1101  { // && ST_BIND(sym.info) != STB_WEAK) {
1102  if (sym.shndx && meta->relocated)
1103  {
1104  sym.value += meta->load_base;
1105  }
1106  }
1107  }
1108 
1109  return y != 0;
1110 }
1111 
1112 bool findSymbol(
1113  const char *symbol, object_meta_t *meta, ElfSymbol_t &sym,
1114  LookupPolicy policy)
1115 {
1116  if (!meta)
1117  {
1118  return false;
1119  }
1120 
1121  // Do we override or not?
1122  std::map<std::string, uintptr_t>::iterator it =
1123  g_LibLoadSymbols.find(std::string(symbol));
1124  if (it != g_LibLoadSymbols.end())
1125  {
1126  if (it->first == symbol)
1127  {
1128  sym.value = it->second;
1129  return true;
1130  }
1131  }
1132 
1133  object_meta_t *ext_meta = meta;
1134  while (ext_meta->parent)
1135  {
1136  ext_meta = ext_meta->parent;
1137  }
1138 
1139  // Try preloads.
1140  for (std::list<object_meta_t *>::iterator it = ext_meta->preloads.begin();
1141  it != ext_meta->preloads.end(); ++it)
1142  {
1143  if (lookupSymbol(symbol, *it, sym, false))
1144  return true;
1145  }
1146 
1147  // If we are allowed, check for non-weak symbols in this binary.
1148  if (policy != NotThisObject && policy != LocalLast)
1149  {
1150  if (lookupSymbol(symbol, meta, sym, false, false))
1151  return true;
1152  }
1153 
1154  // Try the parent object.
1155  if ((meta != ext_meta) && lookupSymbol(symbol, ext_meta, sym, false))
1156  return true;
1157 
1158  // Now, try any loaded objects we might have.
1159  for (std::list<object_meta_t *>::iterator it = ext_meta->objects.begin();
1160  it != ext_meta->objects.end(); ++it)
1161  {
1162  if (*it == meta)
1163  continue; // Already handling.
1164 
1165  if (lookupSymbol(symbol, *it, sym, false))
1166  {
1167  return true;
1168  }
1169  }
1170 
1171  // Try a local lookup if not found.
1172  if (policy == LocalLast)
1173  {
1174  if (lookupSymbol(symbol, meta, sym, false, false))
1175  return true;
1176  }
1177 
1178  // Try libraries again but accept weak symbols.
1179  for (std::list<object_meta_t *>::iterator it = ext_meta->objects.begin();
1180  it != ext_meta->objects.end(); ++it)
1181  {
1182  if (*it == meta)
1183  continue; // Already handling this object.
1184 
1185  if (lookupSymbol(symbol, *it, sym, true))
1186  {
1187  return true;
1188  }
1189  }
1190 
1191  // Try weak symbols in the parent object.
1192  if ((meta != ext_meta) && lookupSymbol(symbol, ext_meta, sym, true))
1193  return true;
1194 
1195  // No luck? Try weak symbols in the main object.
1196  if (policy != NotThisObject)
1197  {
1198  if (lookupSymbol(symbol, meta, sym, true))
1199  return true;
1200  }
1201 
1202  return false;
1203 }
1204 
1205 std::string
1206 symbolName(const ElfSymbol_t &sym, object_meta_t *meta, bool bNoDynamic)
1207 {
1208  if (!meta)
1209  {
1210  return std::string("");
1211  }
1212  else if (sym.name == 0)
1213  {
1214  return std::string("");
1215  }
1216 
1217  const char *strtab = meta->strtab;
1218 
1219  if (ST_TYPE(sym.info) == 3)
1220  {
1221  strtab = meta->shstrtab;
1222  }
1223  else if ((!bNoDynamic) && meta->dyn_strtab)
1224  {
1225  strtab = meta->dyn_strtab;
1226  }
1227 
1228  const char *name = strtab + sym.name;
1229  return std::string(name);
1230 }
1231 
1232 void doRelocation(object_meta_t *meta)
1233 {
1234  if (meta->rel)
1235  {
1236  for (size_t i = 0; i < (meta->rel_sz / sizeof(ElfRel_t)); i++)
1237  {
1238  doThisRelocation(meta->rel[i], meta);
1239  }
1240  }
1241 
1242  if (meta->rela)
1243  {
1244  for (size_t i = 0; i < (meta->rela_sz / sizeof(ElfRela_t)); i++)
1245  {
1246  doThisRelocation(meta->rela[i], meta);
1247  }
1248  }
1249 
1250  // Relocated binaries need to have the GOTPLT fixed up, as each entry points
1251  // to a non-relocated address (that is also not relative).
1252  if (meta->relocated)
1253  {
1254  uintptr_t base = meta->load_base;
1255 
1256  if (meta->plt_rel)
1257  {
1258  for (size_t i = 0; i < (meta->plt_sz / sizeof(ElfRel_t)); i++)
1259  {
1260  uintptr_t *addr =
1261  (uintptr_t *) (base + meta->plt_rel[i].offset);
1262  *addr += base;
1263  }
1264  }
1265 
1266  if (meta->plt_rela)
1267  {
1268  for (size_t i = 0; i < (meta->plt_sz / sizeof(ElfRela_t)); i++)
1269  {
1270  uintptr_t *addr =
1271  (uintptr_t *) (base + meta->plt_rela[i].offset);
1272  *addr += base;
1273  }
1274  }
1275  }
1276 
1277  // Now that relocation is complete, set permissions for program headers.
1278  for (size_t i = 0; i < meta->num_phdrs; i++)
1279  {
1280  if (meta->phdrs[i].type != PT_LOAD)
1281  continue;
1282 
1283  // Loadable data - use the flags to determine how we'll mmap.
1284  int flags = PROT_READ;
1285  if (meta->phdrs[i].flags & PF_X)
1286  flags |= PROT_EXEC;
1287  if (meta->phdrs[i].flags & PF_W)
1288  flags |= PROT_WRITE;
1289  if ((meta->phdrs[i].flags & PF_R) == 0)
1290  flags &= ~PROT_READ;
1291 
1292  // mprotect accordingly.
1293  size_t alignExtra = meta->phdrs[i].vaddr & (getpagesize() - 1);
1294  uintptr_t protectaddr = meta->phdrs[i].vaddr & ~(getpagesize() - 1);
1295 #ifdef DEBUG_LIBLOAD
1296  klog(
1297  LOG_INFO, "map %s %p -> %p [%p] %s%s%s", meta->filename.c_str(),
1298  meta->phdrs[i].vaddr, meta->phdrs[i].vaddr + meta->phdrs[i].memsz,
1299  meta->phdrs[i].offset, flags & PROT_READ ? "r" : "-",
1300  flags & PROT_WRITE ? "w" : "-", flags & PROT_EXEC ? "x" : "-");
1301 #endif
1302  mprotect(
1303  (void *) protectaddr, meta->phdrs[i].memsz + alignExtra, flags);
1304  }
1305 }
1306 
1307 #define R_X86_64_NONE 0
1308 #define R_X86_64_64 1
1309 #define R_X86_64_PC32 2
1310 #define R_X86_64_GOT32 3
1311 #define R_X86_64_PLT32 4
1312 #define R_X86_64_COPY 5
1313 #define R_X86_64_GLOB_DAT 6
1314 #define R_X86_64_JUMP_SLOT 7
1315 #define R_X86_64_RELATIVE 8
1316 #define R_X86_64_GOTPCREL 9
1317 #define R_X86_64_32 10
1318 #define R_X86_64_32S 11
1319 #define R_X86_64_PC64 24
1320 #define R_X86_64_GOTOFF64 25
1321 #define R_X86_64_GOTPC32 26
1322 #define R_X86_64_GOT64 27
1323 #define R_X86_64_GOTPCREL64 28
1324 #define R_X86_64_GOTPC64 29
1325 #define R_X86_64_GOTPLT64 30
1326 #define R_X86_64_PLTOFF64 31
1327 
1328 #define R_386_NONE 0
1329 #define R_386_32 1
1330 #define R_386_PC32 2
1331 #define R_386_GOT32 3
1332 #define R_386_PLT32 4
1333 #define R_386_COPY 5
1334 #define R_386_GLOB_DAT 6
1335 #define R_386_JMP_SLOT 7
1336 #define R_386_RELATIVE 8
1337 #define R_386_GOTOFF 9
1338 #define R_386_GOTPC 10
1339 
1340 uintptr_t doThisRelocation(ElfRel_t rel, object_meta_t *meta)
1341 {
1342  const ElfSymbol_t *symtab = meta->symtab;
1343  if (meta->dyn_symtab)
1344  {
1345  symtab = meta->dyn_symtab;
1346  }
1347 
1348  const ElfSymbol_t *sym = &symtab[R_SYM(rel.info)];
1349  ElfSectionHeader_t *sh = 0;
1350  if (sym->shndx)
1351  {
1352  sh = &meta->shdrs[sym->shndx];
1353  }
1354 
1355  uintptr_t B = meta->load_base;
1356  uintptr_t P = rel.offset;
1357  if (meta->relocated)
1358  {
1359  P += B;
1360  }
1361 
1362  uintptr_t A = *((uintptr_t *) P);
1363  uintptr_t S = 0;
1364 
1365  std::string symbolname = symbolName(*sym, meta);
1366  size_t symbolSize = sizeof(uintptr_t);
1367 
1368  // Patch in section header?
1369  if (symtab && ST_TYPE(sym->info) == 3)
1370  {
1371  if (!sh)
1372  {
1373  printf(
1374  "symbol lookup for '%s' needed a section header, which wasn't "
1375  "present.\n",
1376  symbolname.c_str());
1377  return 0;
1378  }
1379  S = sh->addr;
1380  }
1381  else if (R_TYPE(rel.info) != R_386_RELATIVE)
1382  {
1383  if (sym->name == 0)
1384  {
1385  S = sym->value;
1386  }
1387  else
1388  {
1389  ElfSymbol_t lookupsym;
1390  LookupPolicy policy = LocalFirst;
1391  if (R_TYPE(rel.info) == R_386_COPY)
1392  {
1393  policy = NotThisObject;
1394  }
1395 
1396  // Attempt to find the symbol.
1397  if (!findSymbol(symbolname.c_str(), meta, lookupsym, policy))
1398  {
1399  printf(
1400  "symbol lookup for '%s' (needed in '%s') failed.\n",
1401  symbolname.c_str(), meta->path.c_str());
1402  lookupsym.value = ~0UL;
1403  }
1404 
1405  S = lookupsym.value;
1406  symbolSize = lookupsym.size;
1407  }
1408  }
1409 
1410  if (S == ~0UL)
1411  {
1412  S = 0;
1413  }
1414 
1415  uint32_t result = A;
1416  switch (R_TYPE(rel.info))
1417  {
1418  case R_386_NONE:
1419  break;
1420  case R_386_32:
1421  result = S + A;
1422  break;
1423  case R_386_PC32:
1424  result = S + A - P;
1425  break;
1426  case R_386_JMP_SLOT:
1427  case R_386_GLOB_DAT:
1428  result = S;
1429  break;
1430  case R_386_COPY:
1431  // Only copy if not null.
1432  if (S)
1433  {
1434  memcpy((void *) P, (void *) S, symbolSize);
1435  result = P;
1436  }
1437  break;
1438  case R_386_RELATIVE:
1439  result = B + A;
1440  break;
1441  }
1442 
1443  if (R_TYPE(rel.info) != R_386_COPY)
1444  {
1445  *((uint32_t *) P) = result;
1446  }
1447  return result;
1448 }
1449 
1450 uintptr_t doThisRelocation(ElfRela_t rel, object_meta_t *meta)
1451 {
1452  const ElfSymbol_t *symtab = meta->symtab;
1453  if (meta->dyn_symtab)
1454  {
1455  symtab = meta->dyn_symtab;
1456  }
1457 
1458  const ElfSymbol_t *sym = &symtab[R_SYM(rel.info)];
1459  ElfSectionHeader_t *sh = 0;
1460  if (sym->shndx)
1461  {
1462  sh = &meta->shdrs[sym->shndx];
1463  }
1464 
1465  uintptr_t B = meta->load_base;
1466  uintptr_t P = rel.offset;
1467  if (meta->relocated)
1468  {
1469  P += B;
1470  }
1471 
1472  uintptr_t A = rel.addend;
1473  uintptr_t S = 0;
1474 
1475  std::string symbolname = symbolName(*sym, meta);
1476  size_t symbolSize = sizeof(uintptr_t);
1477 
1478  // Patch in section header?
1479  if (symtab && ST_TYPE(sym->info) == 3)
1480  {
1481  if (!sh)
1482  {
1483  printf(
1484  "symbol lookup for '%s' needed a section header, which wasn't "
1485  "present.\n",
1486  symbolname.c_str());
1487  return 0;
1488  }
1489  S = sh->addr;
1490  }
1491  else if (R_TYPE(rel.info) != R_X86_64_RELATIVE)
1492  {
1493  if (sym->name == 0)
1494  {
1495  S = sym->value;
1496  }
1497  else
1498  {
1499  ElfSymbol_t lookupsym;
1500  LookupPolicy policy = LocalFirst;
1501  if (R_TYPE(rel.info) == R_X86_64_COPY)
1502  {
1503  policy = NotThisObject;
1504  }
1505 
1506  // Attempt to find the symbol.
1507  if (!findSymbol(symbolname.c_str(), meta, lookupsym, policy))
1508  {
1509  printf(
1510  "symbol lookup for '%s' (needed in '%s') failed.\n",
1511  symbolname.c_str(), meta->path.c_str());
1512  lookupsym.value = ~0UL;
1513  }
1514 
1515  S = lookupsym.value;
1516  symbolSize = lookupsym.size;
1517  }
1518  }
1519 
1520  // Valid S?
1521  if ((S == 0) && (R_TYPE(rel.info) != R_X86_64_RELATIVE))
1522  {
1523  return ~0UL;
1524  }
1525 
1526  // Weak symbol.
1527  if (S == ~0UL)
1528  {
1529  S = 0;
1530  }
1531 
1532  uintptr_t result = *((uintptr_t *) P);
1533  switch (R_TYPE(rel.info))
1534  {
1535  case R_X86_64_NONE:
1536  break;
1537  case R_X86_64_64:
1538  result = S + A;
1539  break;
1540  case R_X86_64_PC32:
1541  result = (S + A - P) & 0xFFFFFFFF;
1542  break;
1543  case R_X86_64_COPY:
1544  // Only copy if not null.
1545  if (S)
1546  {
1547  memcpy((void *) P, (void *) S, symbolSize);
1548  result = P;
1549  }
1550  break;
1551  case R_X86_64_JUMP_SLOT:
1552  case R_X86_64_GLOB_DAT:
1553  result = S;
1554  break;
1555  case R_X86_64_RELATIVE:
1556  result = B + A;
1557  break;
1558  case R_X86_64_32:
1559  case R_X86_64_32S:
1560  // From SysV AMD64 ABI 4.4.1
1561  // "The linker must verify that the generated value for the
1562  // R_X86_64_32 (R_X86_64_32S) relocation zero-extends (sign-extends)
1563  // to the original 64-bit value"
1564  result = (S + A) & 0xFFFFFFFF;
1565  break;
1566  default:
1567  klog(
1568  LOG_WARNING,
1569  "libload: unsupported relocation for '%s' in %s: %d",
1570  symbolname.c_str(), meta->filename.c_str(), R_TYPE(rel.info));
1571  }
1572 
1573  if (R_TYPE(rel.info) != R_X86_64_COPY)
1574  {
1575  *((uintptr_t *) P) = result;
1576  }
1577  return result;
1578 }
1579 
1580 #ifdef X86_COMMON
1581 typedef float xmm_t __attribute__((__vector_size__(16)));
1582 xmm_t fixup_xmm_save[8] __attribute__((aligned(16)));
1583 #endif
1584 
1585 extern "C" uintptr_t _libload_dofixup(uintptr_t id, uintptr_t symbol)
1586 {
1587  object_meta_t *meta = (object_meta_t *) id;
1588  uintptr_t returnaddr = 0;
1589 
1590 // Save FP state (glue may use SSE, and we are not called by normal means
1591 // so there's no caller-save).
1592 #ifdef X86_COMMON
1593  xmm_t *fixup_xmm_save = (xmm_t *) memalign(16, sizeof(xmm_t) * 8);
1594 #define XMM_SAVE(N) \
1595  asm volatile("movdqa %%xmm" #N ", %0" : "=m"(fixup_xmm_save[N]));
1596 #define XMM_RESTORE(N) \
1597  asm volatile("movdqa %0, %%xmm" #N ::"m"(fixup_xmm_save[N]));
1598  XMM_SAVE(0);
1599  XMM_SAVE(1);
1600  XMM_SAVE(2);
1601  XMM_SAVE(3);
1602  XMM_SAVE(4);
1603  XMM_SAVE(5);
1604  XMM_SAVE(6);
1605  XMM_SAVE(7);
1606 #endif
1607 
1608 #ifdef BITS_32
1609  ElfRel_t rel = meta->plt_rel[symbol / sizeof(ElfRel_t)];
1610 #else
1611  ElfRela_t rel = meta->plt_rela[symbol];
1612 #endif
1613 
1614  // Verify the symbol is sane.
1615  if (meta->hash && (R_SYM(rel.info) > meta->hash->nchain))
1616  {
1617  fprintf(stderr, "symbol lookup failed (symbol not in hash table)\n");
1618  abort();
1619  }
1620 
1621  uintptr_t result = doThisRelocation(rel, meta);
1622  if (result == ~0UL)
1623  {
1624  fprintf(stderr, "symbol lookup failed (couldn't relocate)\n");
1625  abort();
1626  }
1627 
1628 #ifdef X86_COMMON
1629  XMM_RESTORE(0);
1630  XMM_RESTORE(1);
1631  XMM_RESTORE(2);
1632  XMM_RESTORE(3);
1633  XMM_RESTORE(4);
1634  XMM_RESTORE(5);
1635  XMM_RESTORE(6);
1636  XMM_RESTORE(7);
1637  free(fixup_xmm_save);
1638 #endif
1639 
1640  return result;
1641 }
1642 
1643 #include <dlfcn.h>
1644 
1645 void *_libload_dlopen(const char *file, int mode)
1646 {
1647  object_meta_t *result = 0;
1648 
1649  std::set<std::string>::iterator it =
1650  g_LoadedObjects.find(std::string(file));
1651  if (it != g_LoadedObjects.end())
1652  {
1654  fprintf(stderr, "Not yet able to dlopen already-opened objects.\n");
1655  return 0;
1656  }
1657 
1658  bool bLoad = loadSharedObjectHelper(file, g_MainObject, &result);
1659  if (!bLoad)
1660  {
1661  fprintf(stderr, "Loading object '%s' failed.\n", file);
1662  return 0;
1663  }
1664 
1665  if (result->init_func)
1666  {
1667  init_fini_func_t init = (init_fini_func_t) result->init_func;
1668  init();
1669  }
1670 
1671  return (void *) result;
1672 }
1673 
1674 void *_libload_dlsym(void *handle, const char *name)
1675 {
1676  if (!handle)
1677  return 0;
1678 
1679  object_meta_t *obj = (object_meta_t *) handle;
1680 
1681  ElfSymbol_t sym;
1682  bool bFound = findSymbol(name, obj, sym);
1683  if (!bFound)
1684  {
1685  return 0;
1686  }
1687 
1688  return (void *) sym.value;
1689 }
1690 
1691 int _libload_dlclose(void *handle)
1692 {
1693  return 0;
1694 }
Definition: elf.h:84
xmm_t fixup_xmm_save[8] __attribute__((aligned(16)))