diff options
-rw-r--r-- | include/libelfu/fixup.h | 9 | ||||
-rw-r--r-- | include/libelfu/libelfu.h | 1 | ||||
-rw-r--r-- | src/fixup/phdr.c | 41 |
3 files changed, 51 insertions, 0 deletions
diff --git a/include/libelfu/fixup.h b/include/libelfu/fixup.h new file mode 100644 index 0000000..6fb6620 --- /dev/null +++ b/include/libelfu/fixup.h @@ -0,0 +1,9 @@ +#ifndef __LIBELFU_FIXUP_H__ +#define __LIBELFU_FIXUP_H__ + +#include <libelf.h> +#include <gelf.h> + +void elfu_fixupPhdrSelfRef(Elf *e); + +#endif diff --git a/include/libelfu/libelfu.h b/include/libelfu/libelfu.h index 28a1e9a..271b0ce 100644 --- a/include/libelfu/libelfu.h +++ b/include/libelfu/libelfu.h @@ -5,6 +5,7 @@ #include <libelfu/types.h> #include <libelfu/analysis.h> +#include <libelfu/fixup.h> #include <libelfu/lookup.h> #include <libelfu/model.h> diff --git a/src/fixup/phdr.c b/src/fixup/phdr.c new file mode 100644 index 0000000..ccdc021 --- /dev/null +++ b/src/fixup/phdr.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +#include <libelf.h> +#include <gelf.h> + +void elfu_fixupPhdrSelfRef(Elf *e) +{ + GElf_Ehdr ehdr; + size_t i, n; + + if (!gelf_getehdr(e, &ehdr)) { + fprintf(stderr, "gelf_getehdr() failed: %s.", elf_errmsg(-1)); + return; + } + + if (elf_getphdrnum(e, &n)) { + fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1)); + } + + for (i = 0; i < n; i++) { + GElf_Phdr phdr; + + if (gelf_getphdr(e, i, &phdr) != &phdr) { + fprintf(stderr, "gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1)); + continue; + } + + if (phdr.p_type == PT_PHDR) { + phdr.p_offset = ehdr.e_phoff; + phdr.p_filesz = elf32_fsize(ELF_T_PHDR, n, EV_CURRENT); + phdr.p_memsz = phdr.p_filesz; + + if (!gelf_update_phdr (e, i, &phdr)) { + fprintf(stderr, "gelf_update_ehdr() failed: %s\n", elf_errmsg(-1)); + } + } + } + + /* Tell libelf that phdrs have changed */ + elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY); +} |