diff options
author | Eli Zaretskii <eliz@gnu.org> | 2006-03-18 14:51:54 +0000 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2006-03-18 14:51:54 +0000 |
commit | 8daaf78be89633514b94e661945f0814ea3e1f90 (patch) | |
tree | a0b05ee4473d7f60c22bcacd5078f18fbc77e615 /src/unexelf.c | |
parent | 09b7af0a1c6600f4a2412958ae66b885c79ff5f7 (diff) | |
download | emacs-8daaf78be89633514b94e661945f0814ea3e1f90.tar.gz |
[BROKEN_NOCOMBRELOC]: Include assert.h.
(unexec) [BROKEN_NOCOMBRELOC]: Handle platforms whose nocombreloc option
is broken (e.g., MIPS/NetBSD).
Diffstat (limited to 'src/unexelf.c')
-rw-r--r-- | src/unexelf.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/unexelf.c b/src/unexelf.c index 30a35372544..a236b98eab1 100644 --- a/src/unexelf.c +++ b/src/unexelf.c @@ -433,6 +433,9 @@ extern void fatal (const char *msgid, ...); #if __sgi #include <syms.h> /* for HDRR declaration */ #endif /* __sgi */ +#ifdef BROKEN_NOCOMBRELOC +#include <assert.h> +#endif #ifndef MAP_ANON #ifdef MAP_ANONYMOUS @@ -687,6 +690,9 @@ unexec (new_name, old_name, data_start, bss_start, entry_address) int old_mdebug_index; struct stat stat_buf; int old_file_size; +#ifdef BROKEN_NOCOMBRELOC + int unreloc_sections[10], n_unreloc_sections; +#endif /* Open the old file, allocate a buffer of the right size, and read in the file contents. */ @@ -1218,6 +1224,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address) /* This loop seeks out relocation sections for the data section, so that it can undo relocations performed by the runtime linker. */ +#ifndef BROKEN_NOCOMBRELOC for (n = new_file_h->e_shnum - 1; n; n--) { ElfW(Shdr) section = NEW_SECTION_H (n); @@ -1272,6 +1279,81 @@ unexec (new_name, old_name, data_start, bss_start, entry_address) break; } } +#else /* BROKEN_NOCOMBRELOC */ + for (n = 1, n_unreloc_sections = 0; n < new_file_h->e_shnum; n++) + if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data") + || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata") + || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit4") + || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit8") +#ifdef IRIX6_5 /* see above */ + || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".got") +#endif + || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata1") + || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data1")) + { + assert (n_unreloc_sections + < (sizeof (unreloc_sections) / sizeof (unreloc_sections[0]))); + unreloc_sections[n_unreloc_sections++] = n; +#ifdef DEBUG + fprintf (stderr, "section %d: %s\n", n, + old_section_names + NEW_SECTION_H (n).sh_name); +#endif + } + + for (n = new_file_h->e_shnum - 1; n; n--) + { + ElfW(Shdr) section = NEW_SECTION_H (n); + caddr_t reloc, end; + ElfW(Addr) addr, offset; + int target; + + switch (section.sh_type) + { + default: + break; + case SHT_REL: + case SHT_RELA: + /* This code handles two different size structs, but there should + be no harm in that provided that r_offset is always the first + member. */ + for (reloc = old_base + section.sh_offset, + end = reloc + section.sh_size; + reloc < end; + reloc += section.sh_entsize) + { + addr = ((ElfW(Rel) *) reloc)->r_offset; +#ifdef __alpha__ + /* The Alpha ELF binutils currently have a bug that + sometimes results in relocs that contain all + zeroes. Work around this for now... */ + if (addr == 0) + continue; +#endif + for (nn = 0; nn < n_unreloc_sections; nn++) + { + target = unreloc_sections[nn]; + if (NEW_SECTION_H (target).sh_addr <= addr + && addr < (NEW_SECTION_H (target).sh_addr + + NEW_SECTION_H (target).sh_size)) + { + offset = (NEW_SECTION_H (target).sh_addr - + NEW_SECTION_H (target).sh_offset); + memcpy (new_base + addr - offset, + old_base + addr - offset, + sizeof (ElfW(Addr))); +#ifdef DEBUG + fprintf (stderr, "unrelocate: [%08lx] <= %08lx\n", + (long) addr, + (long) *((long *) (new_base + addr - offset))); +#endif + break; + } + } + } + break; + } + } +#endif /* BROKEN_NOCOMBRELOC */ /* Write out new_file, and free the buffers. */ |