diff options
Diffstat (limited to 'src/prelink.h')
-rw-r--r-- | src/prelink.h | 632 |
1 files changed, 632 insertions, 0 deletions
diff --git a/src/prelink.h b/src/prelink.h new file mode 100644 index 0000000..299f1fa --- /dev/null +++ b/src/prelink.h @@ -0,0 +1,632 @@ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011, + 2013 Red Hat, Inc. + Copyright (C) 2008 CodeSourcery. + Written by Jakub Jelinek <jakub@redhat.com>, 2001. + Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef PRELINK_H +#define PRELINK_H + +#include <elf.h> +#include <libelf.h> +#include <gelfx.h> +#include <ftw.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <utime.h> +#include <glob.h> + +#ifndef HAVE_ELF64_BYTE +typedef uint8_t Elf64_Byte; +#endif + +#ifndef DT_GNU_LIBLIST +#define DT_GNU_LIBLIST 0x6ffffef9 +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 +#define DT_GNU_CONFLICT 0x6ffffef8 +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 +#define DT_GNU_PRELINKED 0x6ffffdf5 +#define SHT_GNU_LIBLIST 0x6ffffff7 +#endif + +#if DT_GNU_LIBLIST == 0x6ffffef7 +#undef DT_GNU_LIBLIST +#undef DT_GNU_CONFLICT +#undef SHT_GNU_LIBLIST +#define DT_GNU_LIBLIST 0x6ffffef9 +#define DT_GNU_CONFLICT 0x6ffffef8 +#define SHT_GNU_LIBLIST 0x6ffffff7 +#endif + +#ifndef DT_GNU_HASH +#define DT_GNU_HASH 0x6ffffef5 +#define SHT_GNU_HASH 0x6ffffff6 +#endif + +#ifndef DT_TLSDESC_PLT +#define DT_TLSDESC_PLT 0x6ffffef6 +#endif + +#ifndef DT_MIPS_RLD_VERSION +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 +#endif + +#ifndef R_MIPS_TLS_DTPMOD32 +#define R_MIPS_TLS_DTPMOD32 38 +#define R_MIPS_TLS_DTPREL32 39 +#define R_MIPS_TLS_TPREL32 47 +#endif + +#ifndef R_MIPS_TLS_DTPMOD64 +#define R_MIPS_TLS_DTPMOD64 40 +#define R_MIPS_TLS_DTPREL64 41 +#define R_MIPS_TLS_TPREL64 48 +#endif + +#ifndef R_MIPS_GLOB_DAT +#define R_MIPS_GLOB_DAT 51 +#endif + +#ifndef R_MIPS_COPY +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 +#define STO_MIPS_PLT 0x8 +#define DT_MIPS_PLTGOT 0x70000032 +#define DT_MIPS_RWPLT 0x70000034 +#endif + +#ifndef SHT_MIPS_DWARF +#define SHT_MIPS_DWARF 0x7000001e +#endif + +#ifndef RSS_UNDEF +#define RSS_UNDEF 0 +#endif + +#ifndef R_ARM_TLS_DESC +#define R_ARM_TLS_DESC 13 +#endif + +#ifndef R_ARM_TLS_DTPMOD32 +#define R_ARM_TLS_DTPMOD32 17 +#define R_ARM_TLS_DTPOFF32 18 +#define R_ARM_TLS_TPOFF32 19 +#endif + +#ifndef R_386_IRELATIVE +#define R_386_IRELATIVE 42 +#endif + +#ifndef R_X86_64_IRELATIVE +#define R_X86_64_IRELATIVE 37 +#endif + +#ifndef R_PPC_IRELATIVE +#define R_PPC_IRELATIVE 248 +#endif + +#ifndef R_PPC64_JMP_IREL +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#endif + +#ifndef R_390_IRELATIVE +#define R_390_IRELATIVE 61 +#endif + +#ifndef R_ARM_IRELATIVE +#define R_ARM_IRELATIVE 160 +#endif + +struct prelink_entry; +struct prelink_info; +struct PLArch; +struct opd_lib; + +struct PLAdjust +{ + GElf_Addr start; + GElf_Addr adjust; +}; + +struct section_move +{ + int old_shnum; + int new_shnum; + int *old_to_new; + int *new_to_old; +}; + +typedef struct +{ + Elf *elf, *elfro; + GElf_Ehdr ehdr; + GElf_Phdr *phdr; + Elf_Scn **scn; + GElf_Addr base, end, align; + GElf_Addr mask; + GElf_Addr info[DT_NUM]; + GElf_Addr info_DT_GNU_PRELINKED; + GElf_Addr info_DT_CHECKSUM; + GElf_Addr info_DT_VERNEED, info_DT_VERDEF, info_DT_VERSYM; + GElf_Addr info_DT_GNU_HASH; + GElf_Addr info_DT_TLSDESC_PLT; + GElf_Addr info_DT_MIPS_LOCAL_GOTNO; + GElf_Addr info_DT_MIPS_GOTSYM; + GElf_Addr info_DT_MIPS_SYMTABNO; + GElf_Addr info_DT_MIPS_PLTGOT; +#define DT_GNU_PRELINKED_BIT 50 +#define DT_CHECKSUM_BIT 51 +#define DT_VERNEED_BIT 52 +#define DT_VERDEF_BIT 53 +#define DT_VERSYM_BIT 54 +#define DT_FILTER_BIT 55 +#define DT_AUXILIARY_BIT 56 +#define DT_LOPROC_BIT 57 +#define DT_GNU_HASH_BIT 58 +#define DT_TLSDESC_PLT_BIT 59 + uint64_t info_set_mask; + int fd, fdro; + int lastscn, dynamic; + const char *soname; + const char *filename, *temp_filename; + struct PLArch *arch; + struct PLAdjust *adjust; + /* .mdebug has absolute file offsets in it. */ + GElf_Off mdebug_orig_offset; + Elf_Data undo; + int nadjust; + int permissive; + struct section_move *move; + GElf_Shdr shdr[0]; +} DSO; + +static inline int +dynamic_info_is_set (DSO *dso, int bit) +{ + return ((dso)->info_set_mask & (1ULL << (bit))) != 0; +} + +struct layout_libs; + +struct PLArch +{ + const char *name; + int class; + int machine; + int alternate_machine[3]; + int max_reloc_size; + const char *dynamic_linker; + const char *dynamic_linker_alt; + int R_COPY; + int R_JMP_SLOT; + int R_RELATIVE; + int rtype_class_valid; + int (*arch_adjust) (DSO *dso, GElf_Addr start, GElf_Addr adjust); + int (*adjust_section) (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust); + int (*adjust_dyn) (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start, + GElf_Addr adjust); + int (*adjust_rel) (DSO *dso, GElf_Rel *rel, GElf_Addr start, + GElf_Addr adjust); + int (*adjust_rela) (DSO *dso, GElf_Rela *rela, GElf_Addr start, + GElf_Addr adjust); + int (*prelink_rel) (struct prelink_info *info, GElf_Rel *rel, + GElf_Addr reladdr); + int (*prelink_rela) (struct prelink_info *info, GElf_Rela *rela, + GElf_Addr relaaddr); + int (*prelink_conflict_rel) (DSO *dso, struct prelink_info *info, + GElf_Rel *rel, GElf_Addr reladdr); + int (*prelink_conflict_rela) (DSO *dso, struct prelink_info *info, + GElf_Rela *rela, GElf_Addr relaaddr); + int (*arch_prelink_conflict) (DSO *dso, struct prelink_info *info); + int (*apply_conflict_rela) (struct prelink_info *info, GElf_Rela *rela, + char *buf, GElf_Addr dest_addr); + int (*apply_rel) (struct prelink_info *info, GElf_Rel *rel, char *buf); + int (*apply_rela) (struct prelink_info *info, GElf_Rela *rela, char *buf); + int (*rel_to_rela) (DSO *dso, GElf_Rel *rel, GElf_Rela *rela); + int (*rela_to_rel) (DSO *dso, GElf_Rela *rela, GElf_Rel *rel); + int (*need_rel_to_rela) (DSO *dso, int first, int last); + GElf_Addr (*create_opd) (struct prelink_info *info, int first, int last, + int plt); + int (*read_opd) (DSO *dso, struct prelink_entry *ent); + int (*free_opd) (struct prelink_entry *ent); + /* Return reloc size in bytes for given non-COPY reloc type. */ + int (*reloc_size) (int); +#define RTYPE_CLASS_VALID 8 +#define RTYPE_CLASS_PLT (8|1) +#define RTYPE_CLASS_COPY (8|2) +#define RTYPE_CLASS_TLS (8|4) + int (*reloc_class) (int); + int (*arch_pre_prelink) (DSO *dso); + int (*arch_prelink) (struct prelink_info *info); + int (*arch_undo_prelink) (DSO *dso); + int (*undo_prelink_rel) (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr); + int (*undo_prelink_rela) (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr); + int (*layout_libs_init) (struct layout_libs *l); + int (*layout_libs_pre) (struct layout_libs *l); + int (*layout_libs_post) (struct layout_libs *l); + GElf_Addr mmap_base, mmap_end; + /* max_page_size is the ELF page size (ELF_MAXPAGESIZE in bfd), + page_size is PAGE_SIZE the architecture typically has, + or if there are more typical sizes, the smallest one. + It doesn't need to be the absolutely smallest supported one, + prelink only optimizes for such page_size. */ + GElf_Addr max_page_size, page_size; +} __attribute__((aligned(64))); + +DSO * open_dso (const char *name); +DSO * fdopen_dso (int fd, const char *name); +struct section_move *init_section_move (DSO *dso); +void add_section (struct section_move *move, int sec); +void remove_section (struct section_move *move, int sec); +int reopen_dso (DSO *dso, struct section_move *move, const char *); +int adjust_symbol_p (DSO *dso, GElf_Sym *sym); +int check_dso (DSO *dso); +int dso_is_rdwr (DSO *dso); +void read_dynamic (DSO *dso); +int set_dynamic (DSO *dso, GElf_Word tag, GElf_Addr value, int fatal); +int addr_to_sec (DSO *dso, GElf_Addr addr); +int adjust_dso (DSO *dso, GElf_Addr start, GElf_Addr adjust); +int adjust_nonalloc (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int first, + GElf_Addr start, GElf_Addr adjust); +int adjust_dso_nonalloc (DSO *dso, int first, GElf_Addr start, + GElf_Addr adjust); +int recompute_nonalloc_offsets (DSO *dso); +int adjust_stabs (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust); +int adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust); +int adjust_mdebug (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust); +int finalize_mdebug (DSO *dso); +int relocate_dso (DSO *dso, GElf_Addr base); +int copy_fd_to_file (int fdin, const char *name, struct stat64 *st); +int update_dso (DSO *dso, const char *); +int prepare_write_dso (DSO *dso); +int write_dso (DSO *dso); +int close_dso (DSO *dso); +GElf_Addr adjust_old_to_new (DSO *dso, GElf_Addr addr); +GElf_Addr adjust_new_to_old (DSO *dso, GElf_Addr addr); +int strtabfind (DSO *dso, int strndx, const char *name); +int shstrtabadd (DSO *dso, const char *name); +int dso_has_bad_textrel (DSO *dso); + +/* data.c */ + +/* Used for reading consecutive blocks of data from a DSO. */ +struct data_iterator { + /* The DSO that is being read. */ + DSO *dso; + + /* The data block that contained the last byte to be read. + NULL if no data has been read yet or if the end of the + DSO has been reached. */ + Elf_Data *data; + + /* The section that contains DATA, when DATA is nonnull. */ + int sec; + + /* The address of the next byte. */ + GElf_Addr addr; + + /* The offset of the next byte from the start of SEC, when DATA + is nonnull. */ + GElf_Addr sec_offset; +}; + +unsigned char * get_data (DSO *dso, GElf_Addr addr, int *scnp, Elf_Type *typep); +#define READWRITEPROTO(le,nn) \ +uint##nn##_t buf_read_u##le##nn (unsigned char *data); \ +uint##nn##_t read_u##le##nn (DSO *dso, GElf_Addr addr); \ +void buf_write_##le##nn (unsigned char *data, uint##nn##_t val);\ +int write_##le##nn (DSO *dso, GElf_Addr addr, uint##nn##_t val); +#define READWRITEPROTOSIZE(nn) \ +READWRITEPROTO(le,nn) \ +READWRITEPROTO(be,nn) \ +uint##nn##_t buf_read_une##nn (DSO *dso, unsigned char *data); \ +uint##nn##_t read_une##nn (DSO *dso, GElf_Addr addr); \ +void buf_write_ne##nn (DSO *dso, unsigned char *data, \ + uint##nn##_t val); \ +void write_ne##nn (DSO *dso, GElf_Addr addr, uint##nn##_t val); +READWRITEPROTO(,8) +READWRITEPROTOSIZE(16) +READWRITEPROTOSIZE(32) +READWRITEPROTOSIZE(64) +#undef READWRITEPROTO +#undef READWRITEPROTOSIZE +const char * strptr (DSO *dso, int sec, off_t offset); +void init_data_iterator (struct data_iterator *it, DSO *dso, GElf_Addr addr); +unsigned char *get_data_from_iterator (struct data_iterator *it, + GElf_Addr size); +int get_sym_from_iterator (struct data_iterator *it, GElf_Sym *sym); + +#define PL_ARCH(F) \ +static struct PLArch plarch_##F __attribute__((section("pl_arch"),used)) + +#define addr_adjust(addr, start, adjust) \ + do { \ + if (addr >= start) \ + addr += adjust; \ + } while (0) + +struct prelink_cache_entry +{ + uint32_t filename; + uint32_t depends; + uint32_t checksum; +#define PCF_UNPRELINKABLE 0x40000 +#define PCF_PRELINKED 0x20000 +#define PCF_ELF64 0x10000 +#define PCF_MACHINE 0x0ffff + uint32_t flags; + uint32_t ctime; + uint32_t mtime; + uint64_t base; + uint64_t end; +}; + +struct prelink_cache +{ +#define PRELINK_CACHE_NAME "prelink-ELF" +#define PRELINK_CACHE_VER "0.3.2" +#define PRELINK_CACHE_MAGIC PRELINK_CACHE_NAME PRELINK_CACHE_VER + const char magic [sizeof (PRELINK_CACHE_MAGIC) - 1]; + uint32_t nlibs; + uint32_t ndeps; + uint32_t len_strings; + uint32_t unused[9]; + struct prelink_cache_entry entry[0]; + /* uint32_t depends [ndeps]; */ + /* const char strings [len_strings]; */ +}; + +struct prelink_link +{ + struct prelink_link *next; + const char *canon_filename; +}; + +struct prelink_entry +{ + const char *filename; + const char *canon_filename; + const char *soname; + struct prelink_link *hardlink; + GElf_Word timestamp; + GElf_Word checksum; + GElf_Addr base, end, layend, pltgot; + dev_t dev; + ino64_t ino; +#define ET_BAD (ET_NUM) +#define ET_CACHE_EXEC (ET_NUM + 1) +#define ET_CACHE_DYN (ET_NUM + 2) +#define ET_UNPRELINKABLE (ET_NUM + 3) + int type, done, ndepends, refs, flags; + union + { + int explicit; + int tmp; + } u; + uint32_t ctime, mtime; + struct prelink_entry **depends; + struct prelink_entry *prev, *next; + struct opd_lib *opd; +}; + +struct prelink_dir +{ + dev_t dev; + struct prelink_dir *next; + size_t len; + int flags; + char dir[0]; +}; + +struct prelink_tls +{ + GElf_Addr modid; + GElf_Addr offset; +}; + +struct prelink_symbol +{ + union + { + struct prelink_entry *ent; + struct prelink_tls *tls; + } u; + struct prelink_symbol *next; + GElf_Addr value; + int reloc_class; +}; + +struct prelink_conflict +{ + struct prelink_conflict *next; + struct prelink_conflict *next2; + /* Object which it was relocated to. */ + union + { + struct prelink_entry *ent; + struct prelink_tls *tls; + } lookup, + /* Object which the relocation was prelinked to. */ + conflict; + /* Offset from start of owner to owner's symbol. */ + GElf_Addr symoff; + /* Value it has in lookup.ent. */ + GElf_Addr lookupval; + /* Value it has in conflict.ent. */ + GElf_Addr conflictval; + int reloc_class; + unsigned char used; + unsigned char ifunc; + char * symname; +}; + +struct prelink_conflicts +{ + struct prelink_conflict *first; + struct prelink_conflict **hash; + struct prelink_conflict **hash2; + size_t count; +}; + +#define conflict_lookup_value(cfl) \ + (((cfl)->reloc_class != RTYPE_CLASS_TLS ? (cfl)->lookup.ent->base : 0) \ + + (cfl)->lookupval) + +struct prelink_info +{ + DSO *dso; + DSO **dsos; + struct prelink_entry *ent; + struct prelink_symbol *symbols; + struct prelink_conflicts *conflicts; + struct prelink_conflicts *curconflicts; + struct prelink_tls *tls, *curtls; + const char **sonames; + char *dynbss, *sdynbss; + GElf_Addr dynbss_base, sdynbss_base; + size_t dynbss_size, sdynbss_size, symtab_entsize; + int symbol_count; + GElf_Sym *symtab; + GElf_Rela *conflict_rela; + size_t conflict_rela_alloced, conflict_rela_size; + GElf_Addr symtab_start, symtab_end; + GElf_Addr (*resolve) (struct prelink_info *info, GElf_Word r_sym, + int reloc_type); + struct prelink_entry *resolveent; + struct prelink_tls *resolvetls; +}; + +int prelink_prepare (DSO *dso); +int prelink (DSO *dso, struct prelink_entry *ent); +int prelink_init_cache (void); +int prelink_load_cache (void); +int prelink_print_cache (void); +int prelink_save_cache (int do_warn); +struct prelink_entry * + prelink_find_entry (const char *filename, const struct stat64 *stp, + int insert); +struct prelink_conflict * + prelink_conflict (struct prelink_info *info, GElf_Word r_sym, + int reloc_type); +GElf_Rela *prelink_conflict_add_rela (struct prelink_info *info); +int prelink_get_relocations (struct prelink_info *info); +int prelink_build_conflicts (struct prelink_info *info); +int update_dynamic_tags (DSO *dso, GElf_Shdr *shdr, GElf_Shdr *old_shdr, + struct section_move *move); +int prelink_exec (struct prelink_info *info); +int prelink_set_checksum (DSO *dso); +int is_ldso_soname (const char *soname); + +int prelink_undo (DSO *dso); + +int prelink_verify (const char *filename); +ssize_t send_file (int outfd, int infd, off_t *poff, size_t count); + +int gather_object (const char *dir, int deref, int onefs); +int read_config (const char *config); +int gather_config (void); +int gather_check_libs (void); +int add_to_blacklist (const char *name, int deref, int onefs); +int blacklist_from_config (void); + +FILE *execve_open (const char *path, char *const argv[], char *const envp[]); +int execve_close (FILE *f); + +int remove_redundant_cxx_conflicts (struct prelink_info *info); +int get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr, + char *buf, GElf_Word size, GElf_Addr dest_addr); + +int layout_libs (void); + +void prelink_all (void); + +int undo_all (void); + +char *prelink_canonicalize (const char *name, struct stat64 *stp); + +extern const char *dynamic_linker; +extern const char *ld_library_path; +extern const char *prelink_cache; +extern const char *prelink_conf; +extern const char *undo_output; +extern int all; +extern int force; +extern int random_base; +extern int conserve_memory; +extern int verbose; +extern int dry_run; +extern int libs_only; +extern int enable_cxx_optimizations; +extern int exec_shield; +extern int undo; +extern int verify; +extern int print_cache; +enum verify_method_t { VERIFY_CONTENT, VERIFY_MD5, VERIFY_SHA }; +extern enum verify_method_t verify_method; +extern int quick; +extern long long seed; +extern GElf_Addr mmap_reg_start, mmap_reg_end, layout_page_size; +extern char *ld_preload; + +extern const char *sysroot; + +extern int allow_bad_textrel; + +int wrap_readlink (const char *path, char *buf, int len); +int wrap_lstat64 (const char *file, struct stat64 *buf); +int wrap_stat64 (const char *file, struct stat64 *buf); +int wrap_open (const char *file, int mode, ...); +int wrap_access (const char *file, int mode); +int wrap_rename (const char *old, const char *new); +int wrap_link (const char *old, const char *new); +int wrap_nftw64 (const char *dir, __nftw64_func_t func, + int descriptors, int flag); +int wrap_utime (const char *file, struct utimbuf *file_times); +int wrap_mkstemp (char *filename); +int wrap_unlink (const char *filename); +ssize_t wrap_listxattr (const char *path, char *list, size_t size); +ssize_t wrap_getxattr (const char *path, const char *name, void *value, + size_t size); +int wrap_setxattr (const char *path, const char *name, const void *value, + size_t size, int flags); +int wrap_glob (const char *pattern, int flags, + int (*errfunc) (const char *epath, int eerrno), + glob_t *pglob); + +char *sysroot_file_name (const char *name, int allow_last_link); + +extern const char *prelink_rtld; + +#endif /* PRELINK_H */ |