e76854c18d
Resolves: #1306793
423 lines
16 KiB
Diff
423 lines
16 KiB
Diff
From 9fa97f0c2c1afae39b6662a836910deb1e0130ad Mon Sep 17 00:00:00 2001
|
|
From: Alan Modra <amodra@gmail.com>
|
|
Date: Sun, 8 Nov 2015 09:28:59 -0800
|
|
Subject: ELF unexec: Tidy code
|
|
|
|
Emacs should build on ppc64el. A problem with the bss has been fixed.
|
|
|
|
This upstream patch has been added [2/10]:
|
|
|
|
ELF unexec: Tidy code
|
|
|
|
Separate out some of the more mechanical changes so following patches
|
|
are smaller.
|
|
|
|
* unexelf.c (unexec): Rearrange initialisation of program
|
|
header vars. Use pointer vars in loops rather than indexing
|
|
section header array via macros. Simplify _OBJC_ sym code
|
|
and reloc handling code.
|
|
|
|
Origin: upstream, commit: 856f4eaba8a76953e0bbcfc7ebb0ca4f2e3cf351
|
|
Bug: http://debbugs.gnu.org/20614
|
|
Bug-Debian: http://bugs.debian.org/808347
|
|
Added-by: Rob Browning <rlb@defaultvalue.org>
|
|
---
|
|
src/unexelf.c | 210 ++++++++++++++++++++++++++--------------------------------
|
|
1 file changed, 96 insertions(+), 114 deletions(-)
|
|
|
|
Index: emacs-24.5/src/unexelf.c
|
|
===================================================================
|
|
--- emacs-24.5.orig/src/unexelf.c
|
|
+++ emacs-24.5/src/unexelf.c
|
|
@@ -813,20 +813,11 @@ unexec (const char *new_name, const char
|
|
if (new_base == MAP_FAILED)
|
|
fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno));
|
|
|
|
- new_file_h = (ElfW (Ehdr) *) new_base;
|
|
- new_program_h = (ElfW (Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
|
|
- new_section_h = (ElfW (Shdr) *)
|
|
- ((byte *) new_base + old_file_h->e_shoff + new_data2_incr);
|
|
-
|
|
/* Make our new file, program and section headers as copies of the
|
|
originals. */
|
|
|
|
+ new_file_h = (ElfW (Ehdr) *) new_base;
|
|
memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
|
|
- memcpy (new_program_h, old_program_h,
|
|
- old_file_h->e_phnum * old_file_h->e_phentsize);
|
|
-
|
|
- /* Modify the e_shstrndx if necessary. */
|
|
- PATCH_INDEX (new_file_h->e_shstrndx);
|
|
|
|
/* Fix up file header. We'll add one section. Section header is
|
|
further away now. */
|
|
@@ -834,6 +825,16 @@ unexec (const char *new_name, const char
|
|
new_file_h->e_shoff += new_data2_incr;
|
|
new_file_h->e_shnum += 1;
|
|
|
|
+ /* Modify the e_shstrndx if necessary. */
|
|
+ PATCH_INDEX (new_file_h->e_shstrndx);
|
|
+
|
|
+ new_program_h = (ElfW (Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
|
|
+ new_section_h = (ElfW (Shdr) *)
|
|
+ ((byte *) new_base + old_file_h->e_shoff + new_data2_incr);
|
|
+
|
|
+ memcpy (new_program_h, old_program_h,
|
|
+ old_file_h->e_phnum * old_file_h->e_phentsize);
|
|
+
|
|
#ifdef UNEXELF_DEBUG
|
|
DEBUG_LOG (old_file_h->e_shoff);
|
|
fprintf (stderr, "Old section count %td\n", (ptrdiff_t) old_file_h->e_shnum);
|
|
@@ -906,32 +907,35 @@ unexec (const char *new_name, const char
|
|
for (n = 1, nn = 1; n < old_file_h->e_shnum; n++, nn++)
|
|
{
|
|
caddr_t src;
|
|
+ ElfW (Shdr) *old_shdr = &OLD_SECTION_H (n);
|
|
+ ElfW (Shdr) *new_shdr = &NEW_SECTION_H (nn);
|
|
+
|
|
/* If it is (s)bss section, insert the new data2 section before it. */
|
|
/* new_data2_index is the index of either old_sbss or old_bss, that was
|
|
chosen as a section for new_data2. */
|
|
if (n == new_data2_index)
|
|
{
|
|
/* Steal the data section header for this data2 section. */
|
|
- memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (old_data_index),
|
|
+ memcpy (new_shdr, &OLD_SECTION_H (old_data_index),
|
|
new_file_h->e_shentsize);
|
|
|
|
- NEW_SECTION_H (nn).sh_addr = new_data2_addr;
|
|
- NEW_SECTION_H (nn).sh_offset = new_data2_offset;
|
|
- NEW_SECTION_H (nn).sh_size = new_data2_size;
|
|
+ new_shdr->sh_addr = new_data2_addr;
|
|
+ new_shdr->sh_offset = new_data2_offset;
|
|
+ new_shdr->sh_size = new_data2_size;
|
|
/* Use the bss section's alignment. This will assure that the
|
|
new data2 section always be placed in the same spot as the old
|
|
bss section by any other application. */
|
|
- NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (n).sh_addralign;
|
|
+ new_shdr->sh_addralign = old_shdr->sh_addralign;
|
|
|
|
/* Now copy over what we have in the memory now. */
|
|
- memcpy (NEW_SECTION_H (nn).sh_offset + new_base,
|
|
- (caddr_t) OLD_SECTION_H (n).sh_addr,
|
|
+ memcpy (new_shdr->sh_offset + new_base,
|
|
+ (caddr_t) old_shdr->sh_addr,
|
|
new_data2_size);
|
|
nn++;
|
|
+ new_shdr++;
|
|
}
|
|
|
|
- memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n),
|
|
- old_file_h->e_shentsize);
|
|
+ memcpy (new_shdr, old_shdr, old_file_h->e_shentsize);
|
|
|
|
if (n == old_bss_index
|
|
/* The new bss and sbss section's size is zero, and its file offset
|
|
@@ -940,13 +944,13 @@ unexec (const char *new_name, const char
|
|
)
|
|
{
|
|
/* NN should be `old_s?bss_index + 1' at this point. */
|
|
- NEW_SECTION_H (nn).sh_offset = new_data2_offset + new_data2_size;
|
|
- NEW_SECTION_H (nn).sh_addr = new_data2_addr + new_data2_size;
|
|
+ new_shdr->sh_offset = new_data2_offset + new_data2_size;
|
|
+ new_shdr->sh_addr = new_data2_addr + new_data2_size;
|
|
/* Let the new bss section address alignment be the same as the
|
|
section address alignment followed the old bss section, so
|
|
this section will be placed in exactly the same place. */
|
|
- NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign;
|
|
- NEW_SECTION_H (nn).sh_size = 0;
|
|
+ new_shdr->sh_addralign = OLD_SECTION_H (nn).sh_addralign;
|
|
+ new_shdr->sh_size = 0;
|
|
}
|
|
else
|
|
{
|
|
@@ -976,53 +980,50 @@ temacs:
|
|
25 1709 0x4 0x10
|
|
*/
|
|
|
|
- if (NEW_SECTION_H (nn).sh_offset >= old_bss_offset
|
|
- || (NEW_SECTION_H (nn).sh_offset + NEW_SECTION_H (nn).sh_size
|
|
+ if (new_shdr->sh_offset >= old_bss_offset
|
|
+ || (new_shdr->sh_offset + new_shdr->sh_size
|
|
> new_data2_offset))
|
|
- NEW_SECTION_H (nn).sh_offset += new_data2_incr;
|
|
+ new_shdr->sh_offset += new_data2_incr;
|
|
|
|
/* Any section that was originally placed after the section
|
|
header table should now be off by the size of one section
|
|
header table entry. */
|
|
- if (NEW_SECTION_H (nn).sh_offset > new_file_h->e_shoff)
|
|
- NEW_SECTION_H (nn).sh_offset += new_file_h->e_shentsize;
|
|
+ if (new_shdr->sh_offset > new_file_h->e_shoff)
|
|
+ new_shdr->sh_offset += new_file_h->e_shentsize;
|
|
}
|
|
|
|
/* If any section hdr refers to the section after the new .data
|
|
section, make it refer to next one because we have inserted
|
|
a new section in between. */
|
|
|
|
- PATCH_INDEX (NEW_SECTION_H (nn).sh_link);
|
|
+ PATCH_INDEX (new_shdr->sh_link);
|
|
/* For symbol tables, info is a symbol table index,
|
|
so don't change it. */
|
|
- if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB
|
|
- && NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
|
|
- PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
|
|
+ if (new_shdr->sh_type != SHT_SYMTAB
|
|
+ && new_shdr->sh_type != SHT_DYNSYM)
|
|
+ PATCH_INDEX (new_shdr->sh_info);
|
|
|
|
if (old_sbss_index != -1)
|
|
- if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".sbss"))
|
|
+ if (!strcmp (old_section_names + new_shdr->sh_name, ".sbss"))
|
|
{
|
|
- NEW_SECTION_H (nn).sh_offset =
|
|
- round_up (NEW_SECTION_H (nn).sh_offset,
|
|
- NEW_SECTION_H (nn).sh_addralign);
|
|
- NEW_SECTION_H (nn).sh_type = SHT_PROGBITS;
|
|
+ new_shdr->sh_offset =
|
|
+ round_up (new_shdr->sh_offset,
|
|
+ new_shdr->sh_addralign);
|
|
+ new_shdr->sh_type = SHT_PROGBITS;
|
|
}
|
|
|
|
/* Now, start to copy the content of sections. */
|
|
- if (NEW_SECTION_H (nn).sh_type == SHT_NULL
|
|
- || NEW_SECTION_H (nn).sh_type == SHT_NOBITS)
|
|
+ if (new_shdr->sh_type == SHT_NULL
|
|
+ || new_shdr->sh_type == SHT_NOBITS)
|
|
continue;
|
|
|
|
/* Write out the sections. .data and .data1 (and data2, called
|
|
".data" in the strings table) get copied from the current process
|
|
instead of the old file. */
|
|
- if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".sdata")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".lit4")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".lit8")
|
|
+ if (!strcmp (old_section_names + new_shdr->sh_name, ".data")
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".sdata")
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".lit4")
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".lit8")
|
|
/* The conditional bit below was in Oliva's original code
|
|
(1999-08-25) and seems to have been dropped by mistake
|
|
subsequently. It prevents a crash at startup under X in
|
|
@@ -1044,28 +1045,22 @@ temacs:
|
|
loader, but I never got anywhere with an SGI support call
|
|
seeking clues. -- fx 2002-11-29. */
|
|
#ifdef IRIX6_5
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".got")
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".got")
|
|
#endif
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".sdata1")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".data1")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".sbss"))
|
|
- src = (caddr_t) OLD_SECTION_H (n).sh_addr;
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".sdata1")
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".data1")
|
|
+ || !strcmp (old_section_names + new_shdr->sh_name, ".sbss"))
|
|
+ src = (caddr_t) old_shdr->sh_addr;
|
|
else
|
|
- src = old_base + OLD_SECTION_H (n).sh_offset;
|
|
+ src = old_base + old_shdr->sh_offset;
|
|
|
|
- memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src,
|
|
- NEW_SECTION_H (nn).sh_size);
|
|
+ memcpy (new_shdr->sh_offset + new_base, src, new_shdr->sh_size);
|
|
|
|
#if defined __alpha__ && !defined __OpenBSD__
|
|
/* Update Alpha COFF symbol table: */
|
|
- if (strcmp (old_section_names + OLD_SECTION_H (n).sh_name, ".mdebug")
|
|
- == 0)
|
|
+ if (strcmp (old_section_names + old_shdr->sh_name, ".mdebug") == 0)
|
|
{
|
|
- pHDRR symhdr = (pHDRR) (NEW_SECTION_H (nn).sh_offset + new_base);
|
|
+ pHDRR symhdr = (pHDRR) (new_shdr->sh_offset + new_base);
|
|
|
|
symhdr->cbLineOffset += new_data2_size;
|
|
symhdr->cbDnOffset += new_data2_size;
|
|
@@ -1082,13 +1077,13 @@ temacs:
|
|
#endif /* __alpha__ && !__OpenBSD__ */
|
|
|
|
#if defined (_SYSTYPE_SYSV)
|
|
- if (NEW_SECTION_H (nn).sh_type == SHT_MIPS_DEBUG
|
|
+ if (new_shdr->sh_type == SHT_MIPS_DEBUG
|
|
&& old_mdebug_index != -1)
|
|
{
|
|
- ptrdiff_t new_offset = NEW_SECTION_H (nn).sh_offset;
|
|
+ ptrdiff_t new_offset = new_shdr->sh_offset;
|
|
ptrdiff_t old_offset = OLD_SECTION_H (old_mdebug_index).sh_offset;
|
|
ptrdiff_t diff = new_offset - old_offset;
|
|
- HDRR *phdr = (HDRR *)(NEW_SECTION_H (nn).sh_offset + new_base);
|
|
+ HDRR *phdr = (HDRR *) (new_shdr->sh_offset + new_base);
|
|
|
|
if (diff)
|
|
{
|
|
@@ -1124,8 +1119,8 @@ temacs:
|
|
n_phdrr->__fileaddr += movement; \
|
|
}
|
|
|
|
- HDRR * o_phdrr = (HDRR *)((byte *)old_base + OLD_SECTION_H (n).sh_offset);
|
|
- HDRR * n_phdrr = (HDRR *)((byte *)new_base + NEW_SECTION_H (nn).sh_offset);
|
|
+ HDRR *o_phdrr = (HDRR *) ((byte *) old_base + old_shdr->sh_offset);
|
|
+ HDRR *n_phdrr = (HDRR *) ((byte *) new_base + new_shdr->sh_offset);
|
|
unsigned movement = new_data2_size;
|
|
|
|
MDEBUGADJUST (idnMax, cbDnOffset);
|
|
@@ -1142,8 +1137,8 @@ temacs:
|
|
requires special handling. */
|
|
if (n_phdrr->cbLine > 0)
|
|
{
|
|
- if (o_phdrr->cbLineOffset > (OLD_SECTION_H (n).sh_offset
|
|
- + OLD_SECTION_H (n).sh_size))
|
|
+ if (o_phdrr->cbLineOffset > (old_shdr->sh_offset
|
|
+ + old_shdr->sh_size))
|
|
{
|
|
/* line data is in a hole in elf. do special copy and adjust
|
|
for this ld mistake.
|
|
@@ -1163,13 +1158,11 @@ temacs:
|
|
#endif /* __sgi */
|
|
|
|
/* If it is the symbol table, its st_shndx field needs to be patched. */
|
|
- if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
|
|
- || NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
|
|
+ if (new_shdr->sh_type == SHT_SYMTAB
|
|
+ || new_shdr->sh_type == SHT_DYNSYM)
|
|
{
|
|
- ElfW (Shdr) *spt = &NEW_SECTION_H (nn);
|
|
- ptrdiff_t num = spt->sh_size / spt->sh_entsize;
|
|
- ElfW (Sym) * sym = (ElfW (Sym) *) (NEW_SECTION_H (nn).sh_offset +
|
|
- new_base);
|
|
+ ptrdiff_t num = new_shdr->sh_size / new_shdr->sh_entsize;
|
|
+ ElfW (Sym) *sym = (ElfW (Sym) *) (new_shdr->sh_offset + new_base);
|
|
for (; num--; sym++)
|
|
{
|
|
if ((sym->st_shndx == SHN_UNDEF)
|
|
@@ -1187,15 +1180,16 @@ temacs:
|
|
{
|
|
byte *symnames;
|
|
ElfW (Sym) *symp, *symendp;
|
|
+ ElfW (Shdr) *sym_shdr = &NEW_SECTION_H (n);
|
|
|
|
- if (NEW_SECTION_H (n).sh_type != SHT_DYNSYM
|
|
- && NEW_SECTION_H (n).sh_type != SHT_SYMTAB)
|
|
+ if (sym_shdr->sh_type != SHT_DYNSYM
|
|
+ && sym_shdr->sh_type != SHT_SYMTAB)
|
|
continue;
|
|
|
|
symnames = ((byte *) new_base
|
|
- + NEW_SECTION_H (NEW_SECTION_H (n).sh_link).sh_offset);
|
|
- symp = (ElfW (Sym) *) (NEW_SECTION_H (n).sh_offset + new_base);
|
|
- symendp = (ElfW (Sym) *) ((byte *)symp + NEW_SECTION_H (n).sh_size);
|
|
+ + NEW_SECTION_H (sym_shdr->sh_link).sh_offset);
|
|
+ symp = (ElfW (Sym) *) (sym_shdr->sh_offset + new_base);
|
|
+ symendp = (ElfW (Sym) *) ((byte *) symp + sym_shdr->sh_size);
|
|
|
|
for (; symp < symendp; symp ++)
|
|
{
|
|
@@ -1219,22 +1213,21 @@ temacs:
|
|
if (strncmp ((char *) (symnames + symp->st_name),
|
|
"_OBJC_", sizeof ("_OBJC_") - 1) == 0)
|
|
{
|
|
- caddr_t old, new;
|
|
+ ElfW (Shdr) *new_shdr = &NEW_SECTION_H (symp->st_shndx);
|
|
+ ptrdiff_t reladdr = symp->st_value - new_shdr->sh_addr;
|
|
+ ptrdiff_t newoff = reladdr + new_shdr->sh_offset;
|
|
|
|
- new = ((symp->st_value - NEW_SECTION_H (symp->st_shndx).sh_addr)
|
|
- + NEW_SECTION_H (symp->st_shndx).sh_offset + new_base);
|
|
/* "Unpatch" index. */
|
|
nn = symp->st_shndx;
|
|
if (nn > old_bss_index)
|
|
nn--;
|
|
if (nn == old_bss_index)
|
|
- memset (new, 0, symp->st_size);
|
|
+ memset (new_base + newoff, 0, symp->st_size);
|
|
else
|
|
{
|
|
- old = ((symp->st_value
|
|
- - NEW_SECTION_H (symp->st_shndx).sh_addr)
|
|
- + OLD_SECTION_H (nn).sh_offset + old_base);
|
|
- memcpy (new, old, symp->st_size);
|
|
+ ElfW (Shdr) *old_shdr = &OLD_SECTION_H (nn);
|
|
+ ptrdiff_t oldoff = reladdr + old_shdr->sh_offset;
|
|
+ memcpy (new_base + newoff, old_base + oldoff, symp->st_size);
|
|
}
|
|
}
|
|
#endif
|
|
@@ -1245,13 +1238,10 @@ temacs:
|
|
that it can undo relocations performed by the runtime linker. */
|
|
for (n = new_file_h->e_shnum; 0 < --n; )
|
|
{
|
|
- ElfW (Shdr) section = NEW_SECTION_H (n);
|
|
-
|
|
- /* Cause a compilation error if anyone uses n instead of nn below. */
|
|
- #define n ((void) 0);
|
|
- n /* Prevent 'macro "n" is not used' warnings. */
|
|
+ ElfW (Shdr) *rel_shdr = &NEW_SECTION_H (n);
|
|
+ ElfW (Shdr) *shdr;
|
|
|
|
- switch (section.sh_type)
|
|
+ switch (rel_shdr->sh_type)
|
|
{
|
|
default:
|
|
break;
|
|
@@ -1260,28 +1250,22 @@ temacs:
|
|
/* This code handles two different size structs, but there should
|
|
be no harm in that provided that r_offset is always the first
|
|
member. */
|
|
- nn = section.sh_info;
|
|
- if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".sdata")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".lit4")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".lit8")
|
|
+ shdr = &NEW_SECTION_H (rel_shdr->sh_info);
|
|
+ if (!strcmp (old_section_names + shdr->sh_name, ".data")
|
|
+ || !strcmp (old_section_names + shdr->sh_name, ".sdata")
|
|
+ || !strcmp (old_section_names + shdr->sh_name, ".lit4")
|
|
+ || !strcmp (old_section_names + shdr->sh_name, ".lit8")
|
|
#ifdef IRIX6_5 /* see above */
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".got")
|
|
+ || !strcmp (old_section_names + shdr->sh_name, ".got")
|
|
#endif
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".sdata1")
|
|
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
|
- ".data1"))
|
|
+ || !strcmp (old_section_names + shdr->sh_name, ".sdata1")
|
|
+ || !strcmp (old_section_names + shdr->sh_name, ".data1"))
|
|
{
|
|
- ElfW (Addr) offset = (NEW_SECTION_H (nn).sh_addr
|
|
- - NEW_SECTION_H (nn).sh_offset);
|
|
- caddr_t reloc = old_base + section.sh_offset, end;
|
|
- for (end = reloc + section.sh_size; reloc < end;
|
|
- reloc += section.sh_entsize)
|
|
+ ElfW (Addr) offset = shdr->sh_addr - shdr->sh_offset;
|
|
+ caddr_t reloc = old_base + rel_shdr->sh_offset, end;
|
|
+ for (end = reloc + rel_shdr->sh_size;
|
|
+ reloc < end;
|
|
+ reloc += rel_shdr->sh_entsize)
|
|
{
|
|
ElfW (Addr) addr = ((ElfW (Rel) *) reloc)->r_offset - offset;
|
|
#ifdef __alpha__
|
|
@@ -1296,8 +1280,6 @@ temacs:
|
|
}
|
|
break;
|
|
}
|
|
-
|
|
- #undef n
|
|
}
|
|
|
|
/* Write out new_file, and free the buffers. */
|