aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/src/space.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/space.c')
-rw-r--r--trunk/src/space.c767
1 files changed, 0 insertions, 767 deletions
diff --git a/trunk/src/space.c b/trunk/src/space.c
deleted file mode 100644
index 4bd4760..0000000
--- a/trunk/src/space.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007 Red Hat, Inc.
- Written by Jakub Jelinek <jakub@redhat.com>, 2001.
-
- 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. */
-
-#include <config.h>
-#include <assert.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include "prelink.h"
-#include "reloc.h"
-#include "space.h"
-
-#define DEBUG_SECTIONS
-
-#ifdef DEBUG_SECTIONS
-void
-print_sections (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
-{
- int elf64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
- int i, j, shf, flag;
- char buf[32], *q;
- const char *p;
- static struct { int sh_type; const char *type_name; } types[] =
- {
- { SHT_NULL, "NULL" },
- { SHT_PROGBITS, "PROGBITS" },
- { SHT_SYMTAB, "SYMTAB" },
- { SHT_STRTAB, "STRTAB" },
- { SHT_RELA, "RELA" },
- { SHT_HASH, "HASH" },
- { SHT_DYNAMIC, "DYNAMIC" },
- { SHT_NOTE, "NOTE" },
- { SHT_NOBITS, "NOBITS" },
- { SHT_REL, "REL" },
- { SHT_SHLIB, "SHLIB" },
- { SHT_DYNSYM, "DYNSYM" },
- { SHT_INIT_ARRAY, "INIT_ARRAY" },
- { SHT_FINI_ARRAY, "FINI_ARRAY" },
- { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" },
- { SHT_GROUP, "GROUP" },
- { SHT_SYMTAB_SHNDX, "SYMTAB SECTION INDICIES" },
- { SHT_GNU_verdef, "VERDEF" },
- { SHT_GNU_verneed, "VERNEED" },
- { SHT_GNU_versym, "VERSYM" },
- { SHT_GNU_LIBLIST, "LIBLIST" },
- { SHT_GNU_HASH, "GNU_HASH" },
- { 0, NULL }
- };
-
- if (elf64)
- printf (" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n");
- else
- printf (" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
- for (i = 0; i < ehdr->e_shnum; ++i)
- {
- p = NULL;
- for (j = 0; types[j].type_name; ++j)
- if (types[j].sh_type == shdr[i].sh_type)
- {
- p = types[j].type_name;
- break;
- }
-
- if (p == NULL)
- {
- if (shdr[i].sh_type >= SHT_LOPROC && shdr[i].sh_type <= SHT_HIPROC)
- sprintf (buf, "LOPROC+%x", shdr[i].sh_type - SHT_LOPROC);
- else if (shdr[i].sh_type >= SHT_LOOS && shdr[i].sh_type <= SHT_HIOS)
- sprintf (buf, "LOOS+%x", shdr[i].sh_type - SHT_LOOS);
- else if (shdr[i].sh_type >= SHT_LOUSER && shdr[i].sh_type <= SHT_HIUSER)
- sprintf (buf, "LOUSER+%x", shdr[i].sh_type - SHT_LOUSER);
- else
- sprintf (buf, "Unknown: %x", shdr[i].sh_type);
- p = buf;
- }
-
- printf (" [%2d] %-17.17s %-15.15s ", i,
- strptr (dso, ehdr->e_shstrndx, shdr[i].sh_name), p);
-
- q = buf;
- shf = shdr[i].sh_flags;
- while (shf)
- {
- flag = shf & -shf;
- shf &= ~flag;
- switch (flag)
- {
- case SHF_WRITE: *q++ = 'W'; break;
- case SHF_ALLOC: *q++ = 'A'; break;
- case SHF_EXECINSTR: *q++ = 'X'; break;
- case SHF_MERGE: *q++ = 'M'; break;
- case SHF_STRINGS: *q++ = 'S'; break;
- case SHF_INFO_LINK: *q++ = 'I'; break;
- case SHF_LINK_ORDER: *q++ = 'L'; break;
- case SHF_OS_NONCONFORMING: *q++ = 'O'; break;
- case SHF_TLS: *q++ = 'T'; break;
- default:
- if (flag & SHF_MASKOS)
- *q++ = 'o', shf &= ~SHF_MASKOS;
- else if (flag & SHF_MASKPROC)
- *q++ = 'p', shf &= ~SHF_MASKPROC;
- else
- *q++ = 'x';
- break;
- }
- }
- *q = '\0';
- if (elf64)
- printf (" %16.16llx %6.6llx %6.6llx %2.2lx %3s %2ld %3lx %2ld\n",
- (long long) shdr[i].sh_addr, (long long) shdr[i].sh_offset,
- (long long) shdr[i].sh_size, (long) shdr[i].sh_entsize,
- buf, (long) shdr[i].sh_link, (long) shdr[i].sh_info,
- (long) shdr[i].sh_addralign);
- else
- printf (" %8.8lx %6.6lx %6.6lx %2.2lx %3s %2ld %3lx %2ld\n",
- (long) shdr[i].sh_addr, (long) shdr[i].sh_offset,
- (long) shdr[i].sh_size, (long) shdr[i].sh_entsize,
- buf, (long) shdr[i].sh_link, (long) shdr[i].sh_info,
- (long) shdr[i].sh_addralign);
- }
-}
-#endif
-
-void
-insert_readonly_section (GElf_Ehdr *ehdr, GElf_Shdr *shdr, int n,
- struct readonly_adjust *adjust)
-{
- int i;
-
- memmove (&shdr[n + 1], &shdr[n],
- (ehdr->e_shnum - n) * sizeof (GElf_Shdr));
- ++ehdr->e_shnum;
- for (i = 0; i < adjust->newcount; ++i)
- if (adjust->new[i] >= n)
- ++adjust->new[i];
-}
-
-int
-remove_readonly_section (GElf_Ehdr *ehdr, GElf_Shdr *shdr, int n,
- struct readonly_adjust *adjust)
-{
- int i, ret = -1;
-
- memmove (&shdr[n], &shdr[n + 1],
- (ehdr->e_shnum - n) * sizeof (GElf_Shdr));
- --ehdr->e_shnum;
- for (i = 0; i < adjust->newcount; ++i)
- if (adjust->new[i] > n)
- --adjust->new[i];
- else if (adjust->new[i] == n)
- {
- adjust->new[i] = -1;
- ret = i;
- }
-
- return ret;
-}
-
-static inline int
-readonly_is_movable (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int k)
-{
- if (! (shdr[k].sh_flags & (SHF_ALLOC | SHF_WRITE)))
- return 0;
-
- switch (shdr[k].sh_type)
- {
- case SHT_HASH:
- case SHT_GNU_HASH:
- case SHT_DYNSYM:
- case SHT_REL:
- case SHT_RELA:
- case SHT_STRTAB:
- case SHT_NOTE:
- case SHT_GNU_verdef:
- case SHT_GNU_verneed:
- case SHT_GNU_versym:
- case SHT_GNU_LIBLIST:
- return 1;
- default:
- if (strcmp (strptr (dso, ehdr->e_shstrndx,
- shdr[k].sh_name), ".interp") == 0)
- return 1;
- return 0;
- }
-}
-
-int
-find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
- GElf_Phdr *phdr, GElf_Shdr *shdr,
- struct readonly_adjust *adjust)
-{
- int i, j;
- GElf_Addr addr;
- GElf_Off p_filesz;
-
- if (add->sh_addr)
- {
- /* Prefer the current address if possible. */
- for (i = 0; i < ehdr->e_phnum; ++i)
- if (phdr[i].p_type == PT_LOAD
- && (phdr[i].p_flags & (PF_R | PF_W)) == PF_R
- && phdr[i].p_vaddr <= add->sh_addr
- && phdr[i].p_vaddr + phdr[i].p_filesz
- >= add->sh_addr + add->sh_size)
- break;
-
- if (i < ehdr->e_phnum)
- for (j = 1; j < ehdr->e_shnum; ++j)
- if ((shdr[j].sh_flags & SHF_ALLOC)
- && shdr[j].sh_addr >= add->sh_addr)
- {
- if (shdr[j].sh_addr >= add->sh_addr + add->sh_size
- && shdr[j - 1].sh_addr + shdr[j - 1].sh_size <= add->sh_addr)
- {
- insert_readonly_section (ehdr, shdr, j, adjust);
- shdr[j] = *add;
- shdr[j].sh_offset = (shdr[j].sh_addr - phdr[i].p_vaddr)
- + phdr[i].p_offset;
- return j;
- }
- break;
- }
- }
-
- for (i = 0; i < ehdr->e_phnum; ++i)
- if (phdr[i].p_type == PT_LOAD
- && (phdr[i].p_flags & (PF_R | PF_W)) == PF_R)
- {
- GElf_Addr start = phdr[i].p_vaddr;
- int after = -1, min;
-
- if (phdr[i].p_offset < ehdr->e_phoff)
- {
- for (j = 0; j < ehdr->e_phnum; j++)
- if (phdr[j].p_type == PT_PHDR
- && phdr[j].p_offset == ehdr->e_phoff
- && phdr[j].p_filesz >= ehdr->e_phnum * ehdr->e_phentsize)
- break;
- start += ehdr->e_phoff;
- if (j < ehdr->e_phnum)
- start += phdr[j].p_filesz;
- else
- start += ehdr->e_phnum * ehdr->e_phentsize;
- start -= phdr[i].p_offset;
- }
- start = (start + add->sh_addralign - 1) & ~(add->sh_addralign - 1);
- for (j = 1; j < ehdr->e_shnum; ++j)
- if ((shdr[j].sh_flags & SHF_ALLOC)
- && shdr[j].sh_addr >= phdr[i].p_vaddr
- && shdr[j].sh_addr + shdr[j].sh_size
- <= phdr[i].p_vaddr + phdr[i].p_filesz)
- {
- if (after == -1)
- after = j - 1;
- if (start + add->sh_size > shdr[j].sh_addr)
- {
- start = shdr[j].sh_addr + shdr[j].sh_size;
- start = (start + add->sh_addralign - 1)
- & ~(add->sh_addralign - 1);
- after = j;
- }
- }
-
- min = -1;
- for (j = i + 1; j < ehdr->e_phnum; ++j)
- if (phdr[j].p_offset >= phdr[i].p_offset + phdr[i].p_filesz
- && (min == -1 || phdr[min].p_offset > phdr[j].p_offset))
- min = j;
-
- if (after != -1
- && (start + add->sh_size <= phdr[i].p_vaddr + phdr[i].p_filesz
- || (phdr[i].p_filesz == phdr[i].p_memsz
- && (min == -1
- || start + add->sh_size - phdr[i].p_vaddr
- <= phdr[min].p_offset))))
- {
- insert_readonly_section (ehdr, shdr, after + 1, adjust);
- shdr[after + 1] = *add;
- shdr[after + 1].sh_addr = start;
- shdr[after + 1].sh_offset = (start - phdr[i].p_vaddr)
- + phdr[i].p_offset;
- if (start + add->sh_size > phdr[i].p_vaddr + phdr[i].p_filesz)
- {
- adjust_nonalloc (dso, ehdr, shdr, 0, 0,
- start + add->sh_size - phdr[i].p_vaddr
- - phdr[i].p_filesz);
- phdr[i].p_filesz = start + add->sh_size - phdr[i].p_vaddr;
- phdr[i].p_memsz = phdr[i].p_filesz;
- }
- return after + 1;
- }
- }
-
- /* If SHT_NOBITS sections are small, just extend the last PT_LOAD
- segment. Small enough here means that the whole .bss fits into
- the same CPU page as the alloced part of it. */
- for (i = -1, j = 0; j < ehdr->e_phnum; ++j)
- if (phdr[j].p_type == PT_LOAD)
- i = j;
- p_filesz = phdr[i].p_filesz;
-
- /* If we'll be converting NOBITS .plt to PROGBITS, account for that in the
- calculation. */
- for (j = 1; j < ehdr->e_shnum; ++j)
- {
- if (shdr[j].sh_type == SHT_NOBITS
- && shdr[j].sh_addr >= phdr[i].p_vaddr
- && shdr[j].sh_addr + shdr[j].sh_size
- <= phdr[i].p_vaddr + phdr[i].p_memsz
- && !strcmp (strptr (dso, ehdr->e_shstrndx, shdr[j].sh_name), ".plt"))
- {
- if (shdr[j].sh_addr + shdr[j].sh_size - phdr[i].p_vaddr > p_filesz)
- p_filesz = shdr[j].sh_addr + shdr[j].sh_size - phdr[i].p_vaddr;
- break;
- }
- }
-
- if (phdr[i].p_filesz
- && p_filesz <= phdr[i].p_memsz
- && !(((phdr[i].p_vaddr + phdr[i].p_memsz - 1)
- ^ (phdr[i].p_vaddr + p_filesz - 1)) & ~(dso->arch->page_size - 1)))
- {
- for (j = 1; j < ehdr->e_shnum; ++j)
- {
- if (!(shdr[j].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_ALLOC)))
- break;
- if (shdr[j].sh_type == SHT_NOBITS
- && (shdr[j].sh_flags & SHF_TLS) == 0
- && shdr[j].sh_addr >= phdr[i].p_vaddr)
- shdr[j].sh_type = SHT_PROGBITS;
- }
-
- insert_readonly_section (ehdr, shdr, j, adjust);
- shdr[j] = *add;
- shdr[j].sh_addr = (shdr[j - 1].sh_addr + shdr[j - 1].sh_size
- + add->sh_addralign - 1) & ~(add->sh_addralign - 1);
- shdr[j].sh_offset = (shdr[j].sh_addr - phdr[i].p_vaddr)
- + phdr[i].p_offset;
- phdr[i].p_filesz = shdr[j].sh_addr + add->sh_size - phdr[i].p_vaddr;
- phdr[i].p_memsz = phdr[i].p_filesz;
- adjust_nonalloc (dso, ehdr, shdr, 0, 0, phdr[i].p_offset
- + phdr[i].p_filesz - shdr[j + 1].sh_offset);
- return j;
- }
-
- /* See if we can decrease binary's base VMA and thus gain space.
- This trick is mainly useful for IA-32. */
- for (i = 0; i < ehdr->e_phnum; ++i)
- if (phdr[i].p_type == PT_LOAD)
- break;
-
- addr = (add->sh_size + add->sh_addralign - 1 + phdr[i].p_align - 1)
- & ~(phdr[i].p_align - 1);
- if (phdr[i].p_align <= dso->arch->page_size
- && phdr[i].p_flags == (PF_R | PF_X)
- && phdr[i].p_filesz == phdr[i].p_memsz
- && phdr[i].p_vaddr - addr
- && ! (((phdr[i].p_vaddr - addr) ^ phdr[i].p_vaddr)
- & ~(phdr[i].p_align * 256 - 1)))
- {
- int moveend;
- if (! adjust->basemove_end)
- {
- for (moveend = 1; moveend < ehdr->e_shnum; ++moveend)
- if (strcmp (strptr (dso, ehdr->e_shstrndx,
- shdr[moveend].sh_name), ".interp")
- && shdr[moveend].sh_type != SHT_NOTE)
- break;
- if (moveend < ehdr->e_shnum && moveend > 1)
- {
- adjust->basemove_end = shdr[moveend].sh_addr;
- adjust->moveend = moveend;
- }
- }
- else
- moveend = adjust->moveend;
- if (moveend < ehdr->e_shnum && moveend > 1
- && (shdr[moveend].sh_flags & (SHF_ALLOC | SHF_WRITE)))
- {
- int k = moveend;
- GElf_Addr adj = addr;
-
- if (add->sh_addr && ! adjust->move2
- && phdr[i].p_vaddr <= add->sh_addr
- && phdr[i].p_vaddr + phdr[i].p_filesz > add->sh_addr)
- {
- for (k = moveend; k < ehdr->e_shnum; ++k)
- {
- if (! (shdr[k].sh_flags & (SHF_ALLOC | SHF_WRITE)))
- {
- k = ehdr->e_shnum;
- break;
- }
-
- if (shdr[k].sh_addr > add->sh_addr)
- {
- /* Don't allow inserting in between reloc sections
- if they are adjacent. Similarly for adjacent
- note sections. */
- int sh_type1 = (shdr[k - 1].sh_type == SHT_RELA)
- ? SHT_REL : shdr[k - 1].sh_type;
- int sh_type2 = (shdr[k].sh_type == SHT_RELA)
- ? SHT_REL : shdr[k].sh_type;
-
- if (sh_type1 != sh_type2)
- break;
-
- if (sh_type1 != SHT_REL && sh_type1 != SHT_NOTE)
- break;
- if ((shdr[k - 1].sh_addr
- + ((shdr[k - 1].sh_size + 3) & -4))
- != shdr[k].sh_addr)
- break;
- }
-
- if (! readonly_is_movable (dso, ehdr, shdr, k))
- {
- k = ehdr->e_shnum;
- break;
- }
- }
-
- if (k < ehdr->e_shnum)
- {
- GElf_Addr a;
-
- a = shdr[k].sh_addr;
- a -= shdr[k - 1].sh_addr + shdr[k - 1].sh_size;
- assert (add->sh_addralign <= phdr[i].p_align);
- assert (add->sh_size > a);
- a = (add->sh_size - a + phdr[i].p_align - 1)
- & ~(phdr[i].p_align - 1);
- if (a < adj)
- {
- adjust->move2 = 1;
- adj = a;
- }
- else
- k = moveend;
- }
- else
- k = moveend;
- }
-
- for (j = 1; j < k; ++j)
- shdr[j].sh_addr -= adj;
- phdr[i].p_vaddr -= adj;
- phdr[i].p_paddr -= adj;
- phdr[i].p_filesz += adj;
- phdr[i].p_memsz += adj;
- for (j = 0; j < ehdr->e_phnum; ++j)
- {
- if (j == i)
- continue;
- /* Leave STACK segment alone, it has p_vaddr == p_paddr == 0
- and p_offset == p_filesz == p_memsz == 0. */
- if (phdr[j].p_type == PT_GNU_STACK)
- continue;
- if (phdr[j].p_vaddr
- < adjust->basemove_end - adjust->basemove_adjust)
- {
- phdr[j].p_vaddr -= adj;
- phdr[j].p_paddr -= adj;
- }
- else
- phdr[j].p_offset += adj;
- }
- adjust->basemove_adjust += adj;
- insert_readonly_section (ehdr, shdr, k, adjust);
- shdr[k] = *add;
- if (k == moveend)
- {
- addr = shdr[k - 1].sh_addr + shdr[k - 1].sh_size;
- addr = (addr + add->sh_addralign - 1) & ~(add->sh_addralign - 1);
- }
- else
- {
- addr = (shdr[k + 1].sh_addr - add->sh_size)
- & ~(add->sh_addralign - 1);
- }
-
- shdr[k].sh_addr = addr;
- shdr[k].sh_offset = (addr - phdr[i].p_vaddr) + phdr[i].p_offset;
- adjust_nonalloc (dso, ehdr, shdr, 0, 0, adj);
- return k;
- }
- }
-
- /* We have to create new PT_LOAD if at all possible. */
- for (j = 0; j < ehdr->e_phnum; ++j)
- if (phdr[j].p_type == PT_NULL)
- break;
-
- if (j < ehdr->e_phnum)
- {
- memmove (phdr, &phdr[j + 1],
- (ehdr->e_phnum - j - 1) * sizeof (GElf_Phdr));
- ehdr->e_phnum--;
- }
- else
- {
- addr = ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
- for (j = 1; j < ehdr->e_shnum; ++j)
- {
- if (addr > shdr[j].sh_offset)
- {
- GElf_Addr start, addstart, endaddr, *old_addr;
- GElf_Addr minsize = ~(GElf_Addr) 0;
- int movesec = -1, last, k, e;
-
- if (ehdr->e_phoff < phdr[i].p_offset
- || ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize
- > phdr[i].p_offset + phdr[i].p_filesz
- || ! readonly_is_movable (dso, ehdr, shdr, j)
- || shdr[j].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
- {
- error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
- dso->filename);
- return 0;
- }
-
- start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
- + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
- for (last = 1; last < ehdr->e_shnum; ++last)
- if (! readonly_is_movable (dso, ehdr, shdr, last)
- || shdr[last].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
- break;
- for (j = 1; j < last; ++j)
- {
- addstart = (start + add->sh_addralign - 1)
- & ~(add->sh_addralign - 1);
- start = (start + shdr[j].sh_addralign - 1)
- & ~(shdr[j].sh_addralign - 1);
- endaddr = -1;
- if (j + 1 < ehdr->e_shnum)
- endaddr = shdr[j + 1].sh_addr;
- if (phdr[i].p_vaddr + phdr[i].p_filesz < endaddr)
- endaddr = phdr[i].p_vaddr + phdr[i].p_filesz;
-
- switch (shdr[j].sh_type)
- {
- case SHT_HASH:
- case SHT_GNU_HASH:
- case SHT_DYNSYM:
- case SHT_STRTAB:
- case SHT_GNU_verdef:
- case SHT_GNU_verneed:
- case SHT_GNU_versym:
- case SHT_GNU_LIBLIST:
- if (endaddr >= start
- && endaddr - start < minsize)
- {
- minsize = endaddr - start;
- movesec = j;
- }
- if (endaddr > addstart
- && endaddr - addstart > add->sh_size
- && endaddr - addstart - add->sh_size
- < minsize)
- {
- minsize = endaddr - addstart - add->sh_size;
- movesec = j;
- }
- break;
- case SHT_REL:
- case SHT_RELA:
- case SHT_NOTE:
- /* Don't allow inserting in between reloc sections
- if they are adjacent. Similarly for adjacent
- note sections. */
- if (j + 1 < ehdr->e_shnum)
- {
- if (shdr[j].sh_type == SHT_NOTE)
- {
- if (shdr[j + 1].sh_type != SHT_NOTE)
- break;
- }
- else if (shdr[j + 1].sh_type != SHT_REL
- && shdr[j + 1].sh_type != SHT_RELA)
- {
- break;
- }
-
- if ((shdr[j].sh_addr
- + ((shdr[j].sh_size + 3) & -4))
- != shdr[j + 1].sh_addr)
- break;
-
- start += shdr[j].sh_size;
- continue;
- }
- break;
- }
-
- if (start + shdr[j].sh_size <= endaddr)
- {
- movesec = j + 1;
- break;
- }
- start += shdr[j].sh_size;
- }
-
- if (movesec == -1)
- {
- error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
- dso->filename);
- return 0;
- }
-
- start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
- + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
- old_addr = (GElf_Addr *) alloca (movesec * sizeof (GElf_Addr));
- for (k = 1; k < movesec; ++k)
- {
- start = (start + shdr[k].sh_addralign - 1)
- & ~(shdr[k].sh_addralign - 1);
- old_addr[k] = shdr[k].sh_addr;
- shdr[k].sh_addr = start;
- shdr[k].sh_offset = start + phdr[i].p_offset
- - phdr[i].p_vaddr;
- start += shdr[k].sh_size;
- }
-
- for (e = 0; e < ehdr->e_phnum; ++e)
- if (phdr[e].p_type != PT_LOAD
- && phdr[e].p_type != PT_GNU_STACK)
- for (k = 1; k < movesec; ++k)
- if (old_addr[k] == phdr[e].p_vaddr)
- {
- if (phdr[e].p_filesz != shdr[k].sh_size
- || phdr[e].p_memsz != shdr[k].sh_size)
- {
- int k1 = -1;
- if (phdr[e].p_type == PT_NOTE
- && shdr[k].sh_type == SHT_NOTE
- && phdr[e].p_filesz == phdr[e].p_memsz)
- {
- k1 = k;
- while (k1 < movesec)
- {
- if (shdr[k1].sh_type != SHT_NOTE
- || shdr[k1].sh_addr - old_addr[k1]
- != shdr[k].sh_addr - old_addr[k]
- || old_addr[k1] + shdr[k1].sh_size
- > phdr[e].p_vaddr + phdr[e].p_filesz)
- {
- k1 = -1;
- break;
- }
- if (old_addr[k1] + shdr[k1].sh_size
- == phdr[e].p_vaddr + phdr[e].p_filesz)
- break;
- ++k1;
- }
- if (k1 == movesec)
- k1 = -1;
- }
- if (k1 == -1)
- {
- error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section",
- dso->filename);
- return 0;
- }
- }
- phdr[e].p_vaddr += shdr[k].sh_addr - old_addr[k];
- phdr[e].p_paddr += shdr[k].sh_addr - old_addr[k];
- phdr[e].p_offset += shdr[k].sh_addr - old_addr[k];
- break;
- }
-
- if (j < last)
- /* Now continue as if there was place for a new PT_LOAD
- in ElfW(Phdr) table initially. */
- break;
- else
- {
- GElf_Shdr moveshdr;
- int newidx, ret, movedidx, oldidx;
-
- moveshdr = shdr[movesec];
- newidx = remove_readonly_section (ehdr, shdr, movesec, adjust);
- oldidx = adjust->move->new_to_old[movesec];
- remove_section (adjust->move, movesec);
- ret = find_readonly_space (dso, add, ehdr, phdr, shdr, adjust);
- if (ret == 0)
- return 0;
- movedidx = find_readonly_space (dso, &moveshdr, ehdr, phdr,
- shdr, adjust);
- if (movedidx == 0)
- return 0;
- if (newidx != -1)
- adjust->new[newidx] = movedidx;
- add_section (adjust->move, movedidx);
- if (oldidx != -1)
- {
- adjust->move->old_to_new[oldidx] = movedidx;
- adjust->move->new_to_old[movedidx] = oldidx;
- }
- if (movedidx <= ret)
- ++ret;
- return ret;
- }
- }
- }
- }
-
- for (i = 0, j = 0; i < ehdr->e_phnum; ++i)
- if (phdr[i].p_type == PT_LOAD)
- j = i;
- else if (phdr[i].p_type == PT_PHDR)
- {
- if (phdr[i].p_filesz == ehdr->e_phnum * ehdr->e_phentsize)
- phdr[i].p_filesz += ehdr->e_phentsize;
- if (phdr[i].p_memsz == ehdr->e_phnum * ehdr->e_phentsize)
- phdr[i].p_memsz += ehdr->e_phentsize;
- }
-
- memmove (&phdr[j + 2], &phdr[j + 1],
- (ehdr->e_phnum - j - 1) * sizeof (GElf_Phdr));
- ++ehdr->e_phnum;
- phdr[++j].p_type = PT_LOAD;
- phdr[j].p_offset = phdr[j - 1].p_offset + phdr[j - 1].p_filesz;
- phdr[j].p_offset = (phdr[j].p_offset + add->sh_addralign - 1)
- & ~(add->sh_addralign - 1);
- phdr[j].p_align = phdr[j - 1].p_align;
- phdr[j].p_vaddr = phdr[j - 1].p_vaddr + phdr[j - 1].p_memsz;
- phdr[j].p_vaddr += (phdr[j].p_align - 1);
- phdr[j].p_vaddr &= ~(phdr[j].p_align - 1);
- phdr[j].p_vaddr += (phdr[j].p_offset & (phdr[j].p_align - 1));
- phdr[j].p_paddr = phdr[j].p_vaddr;
- /* Although the content of the segment is read-only, unless it ends on
- a page boundary, we must make it writeable. This is because the rest of
- the last page in the segment will be used as sbrk area which is assumed
- to be writeable. */
- phdr[j].p_flags = (PF_R | PF_W);
- phdr[j].p_filesz = add->sh_size;
- phdr[j].p_memsz = add->sh_size;
- for (i = 1; i < ehdr->e_shnum; ++i)
- if (! (shdr[i].sh_flags & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR)))
- break;
- assert (i < ehdr->e_shnum);
- insert_readonly_section (ehdr, shdr, i, adjust);
- shdr[i] = *add;
- shdr[i].sh_addr = phdr[j].p_vaddr;
- shdr[i].sh_offset = phdr[j].p_offset;
- adjust_nonalloc (dso, ehdr, shdr, 0, 0,
- phdr[j].p_offset + phdr[j].p_filesz - phdr[j - 1].p_offset
- - phdr[j - 1].p_filesz);
- return i;
-}