binutils-gdb/bfd/elf-nacl.c

206 lines
6.4 KiB
C
Raw Normal View History

bfd/ 2012-04-03 Roland McGrath <mcgrathr@google.com> * elf-nacl.c: New file. * elf-nacl.h: New file. * elf32-i386.c (elf_backend_modify_segment_map): Define for bfd_elf32_i386_nacl_vec. (elf_backend_modify_program_headers): Likewise. * elf64-x86-64.c (elf_backend_modify_segment_map): Define for bfd_elf64_x86_64_nacl_vec and bfd_elf32_x86_64_nacl_vec. (elf_backend_modify_program_headers): Likewise. * Makefile.am (BFD32_BACKENDS, BFD64_BACKENDS): Add elf-nacl.lo here. (BFD32_BACKENDS_CFILES, BFD64_BACKENDS_CFILES): Add elf-nacl.c here. * Makefile.in: Regenerated. * configure.in (bfd_elf64_x86_64_nacl_vec): Add elf-nacl.o to tb here. (bfd_elf32_x86_64_nacl_vec): Likewise. (bfd_elf64_x86_64_vec, bfd_elf32_x86_64_vec): Likewise. (bfd_elf64_x86_64_freebsd_vec, bfd_elf64_x86_64_sol2_vec): Likewise. (bfd_elf64_l1om_vec, bfd_elf64_l1om_freebsd_vec): Likewise. (bfd_elf64_k1om_vec, bfd_elf64_k1om_freebsd_vec): Likewise. (bfd_elf32_i386_nacl_vec): Likewise. (bfd_elf32_i386_sol2_vec, bfd_elf32_i386_freebsd_vec): Likewise. (bfd_elf32_i386_vxworks_vec, bfd_elf32_i386_vec): Likewise. * configure: Regenerated. binutils/testsuite/ 2012-04-03 Roland McGrath <mcgrathr@google.com> * lib/binutils-common.exp (is_elf_format): Consider *-*-nacl* to be ELF too. * binutils-all/elfedit-4.d: Add "#as: --64" option. * binutils-all/i386/i386.exp: Accept nacl targets too. * binutils-all/x86-64/x86-64.exp: Likewise. gas/testsuite/ 2012-04-03 Roland McGrath <mcgrathr@google.com> * gas/i386/k1om.d: Add not-target match for *-*-nacl*. * gas/i386/l1om.d: Likewise. ld/ 2012-04-03 Roland McGrath <mcgrathr@google.com> * configure.tgt (i[3-7]86-*-nacl*, x86_64-*-nacl*): Handle them. * emulparams/elf_nacl.sh: New file. * emulparams/elf_i386_nacl.sh: New file. * emulparams/elf32_x86_64_nacl.sh: New file. * emulparams/elf_x86_64_nacl.sh: New file. * Makefile.am (ALL_EMULATION_SOURCES): Add eelf_i386_nacl.c here. (ALL_64_EMULATION_SOURCES): Add eelf32_x86_64_nacl.c and eelf_x86_64_nacl.c here. (eelf_i386_nacl.c, eelf32_x86_64_nacl.c, eelf_x86_64_nacl.c): New targets. * Makefile.in: Regenerated. * scripttempl/elf.sc: Handle SEPARATE_CODE cases. ld/testsuite/ 2012-04-03 Roland McGrath <mcgrathr@google.com> * ld-x86-64/ilp32-4-nacl.d: New file. * ld-x86-64/x86-64.exp: Run it. * ld-discard/discard.exp: Accept nacl targets too. * ld-elf/binutils.exp: Likewise. * ld-elf/comm-data.exp: Likewise. * ld-elf/elf.exp: Likewise. * ld-elf/tls_common.exp: Likewise. * ld-elfvers/vers.exp: Likewise. * ld-elfvsb/elfvsb.exp: Likewise. * ld-elfweak/elfweak.exp: Likewise. * ld-gc/gc.exp: Likewise. * ld-ifunc/binutils.exp: Likewise. * ld-ifunc/ifunc.exp: Likewise. * ld-linkonce/linkonce.exp:Likewise. * ld-pie/pie.exp: Likewise. * ld-shared/shared.exp: Likewise. * ld-undefined/weak-undef.exp: Likewise. * ld-unique/unique.exp: Likewise. * ld-x86-64/dwarfreloc.exp: Likewise. * ld-x86-64/line.exp: Likewise. * lib/ld-lib.exp (slurp_options): Support global array options_regsub to apply substitutions to the contents of options lines read from the file. * ld-i386/emit-relocs.d: Renamed to ... * ld-i386/emit-relocs.rd: ... this. * ld-i386/i386.exp: Accept nacl targets too. For them, use options_regsub to replace elf_i386 with elf_i386_nacl in run_dump_test cases; apply the same substitution in $i386tests; replace foo.rd expectations files with foo-nacl.rd in $i386tests. (i386tests): Change emit-relocs.d to emit-relocs.rd here. * ld-i386/emit-relocs-nacl.rd: New file. * ld-i386/plt-nacl.pd: New file. * ld-i386/plt-pic-nacl.pd: New file. * ld-i386/tlsbin-nacl.rd: New file. * ld-i386/tlsbindesc-nacl.rd: New file. * ld-i386/tlsdesc-nacl.rd: New file. * ld-i386/tlsgdesc-nacl.rd: New file. * ld-i386/tlsnopic-nacl.rd: New file. * ld-i386/tlspic-nacl.rd: New file. * ld-x86-64/x86-64.exp: Accept nacl targets too. For them, use options_regsub to replace elf_x86_64 with elf_x86_64_nacl in run_dump_test cases; apply the same substitution in $x86_64tests; replace foo.rd expectations files with foo-nacl.rd in $x86_64tests. Add explicit -melf_x86_64 to ld options in tests that need it, in case the default emulation is x32 (as it is for x86_64-nacl). * ld/testsuite/ld-x86-64/plt-nacl.pd: New file. * ld/testsuite/ld-x86-64/split-by-file-nacl.rd: New file. * ld/testsuite/ld-x86-64/tlsbin-nacl.rd: New file. * ld/testsuite/ld-x86-64/tlsbindesc-nacl.rd: New file. * ld/testsuite/ld-x86-64/tlsdesc-nacl.pd: New file. * ld/testsuite/ld-x86-64/tlsdesc-nacl.rd: New file. * ld/testsuite/ld-x86-64/tlsgdesc-nacl.rd: New file. * ld/testsuite/ld-x86-64/tlspic-nacl.rd: New file. * ld-i386/hidden2.d: Loosen regexps to match any file format variant, and not to depend on exact addresses, displacements, etc. where they are irrelevant. * ld-i386/pcrel16.d: Likewise. * ld-i386/pcrel16abs.d: Likewise. * ld-i386/pr12718.d: Likewise. * ld-i386/pr12921.d: Likewise. * ld-i386/reloc.d: Likewise. * ld-i386/tlsbin.dd: Likewise. * ld-i386/tlsbin.sd: Likewise. * ld-i386/tlsbin.td: Likewise. * ld-i386/tlsbindesc.dd: Likewise. * ld-i386/tlsbindesc.sd: Likewise. * ld-i386/tlsbindesc.td: Likewise. * ld-i386/tlsdesc.dd: Likewise. * ld-i386/tlsdesc.sd: Likewise. * ld-i386/tlsdesc.td: Likewise. * ld-i386/tlsg.sd: Likewise. * ld-i386/tlsgdesc.dd: Likewise. * ld-i386/tlsindntpoff.dd: Likewise. * ld-i386/tlsnopic.dd: Likewise. * ld-i386/tlsnopic.sd: Likewise. * ld-i386/tlspic.dd: Likewise. * ld-i386/tlspic.sd: Likewise. * ld-i386/tlspic.td: Likewise. * ld-i386/tlspie2.d: Likewise. * ld-x86-64/hidden2.d: Likewise. * ld-x86-64/pcrel16.d: Likewise. * ld-x86-64/pr12718.d: Likewise. * ld-x86-64/pr12921.d: Likewise. * ld-x86-64/protected3.d: Likewise. * ld-x86-64/tlsbin.dd: Likewise. * ld-x86-64/tlsbin.sd: Likewise. * ld-x86-64/tlsbin.td: Likewise. * ld-x86-64/tlsbindesc.dd: Likewise. * ld-x86-64/tlsbindesc.sd: Likewise. * ld-x86-64/tlsbindesc.td: Likewise. * ld-x86-64/tlsdesc.dd: Likewise. * ld-x86-64/tlsdesc.sd: Likewise. * ld-x86-64/tlsdesc.td: Likewise. * ld-x86-64/tlsg.sd: Likewise. * ld-x86-64/tlsgd5.dd: Likewise. * ld-x86-64/tlsgd6.dd: Likewise. * ld-x86-64/tlsgdesc.dd: Likewise. * ld-x86-64/tlspic.dd: Likewise. * ld-x86-64/tlspic.sd: Likewise. * ld-x86-64/tlspic.td: Likewise. * ld-x86-64/ilp32-8.d: Match any file format variant. Use a -Ttext and adjust expected results, to handle variant layouts. * ld-x86-64/ilp32-9.d: Likewise. * ld-i386/alloc.t: Remove superfluous OUTPUT_FORMAT statement. * ld-i386/pr12627.t: Likewise. * ld-x86-64/abs-l1om.d: Add target: constraint. * ld-x86-64/protected2-l1om.d: Likewise. * ld-x86-64/protected3-l1om.d: Likewise. * ld-x86-64/ilp32-4.d: Likewise. * ld-x86-64/plt.s: New file. * ld-x86-64/pltlib.s: New file. * ld-x86-64/plt.pd: New file. * ld-x86-64/x86-64.exp (x86_64tests): Add them. * ld-i386/plt.s: New file. * ld-i386/pltlib.s: New file. * ld-i386/plt.pd: New file. * ld-i386/plt-pic.s: New file. * ld-i386/plt-pic.pd: New file. * ld-i386/i386.exp (i386tests): Add them.
2012-04-03 18:01:38 +02:00
/* Native Client support for ELF
Copyright 2012 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
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 3 of the License, 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 "sysdep.h"
#include "bfd.h"
#include "elf-bfd.h"
#include "elf-nacl.h"
#include "elf/common.h"
#include "elf/internal.h"
static bfd_boolean
segment_executable (struct elf_segment_map *seg)
{
if (seg->p_flags_valid)
return (seg->p_flags & PF_X) != 0;
else
{
/* The p_flags value has not been computed yet,
so we have to look through the sections. */
unsigned int i;
for (i = 0; i < seg->count; ++i)
if (seg->sections[i]->flags & SEC_CODE)
return TRUE;
}
return FALSE;
}
static bfd_boolean
segment_nonexecutable_and_has_contents (struct elf_segment_map *seg)
{
bfd_boolean any_contents = FALSE;
unsigned int i;
for (i = 0; i < seg->count; ++i)
{
if (seg->sections[i]->flags & SEC_CODE)
return FALSE;
if (seg->sections[i]->flags & SEC_HAS_CONTENTS)
any_contents = TRUE;
}
return any_contents;
}
/* We permute the segment_map to get BFD to do the file layout we want:
The first non-executable PT_LOAD segment appears first in the file
and contains the ELF file header and phdrs. */
bfd_boolean
nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
struct elf_segment_map **m = &elf_tdata (abfd)->segment_map;
struct elf_segment_map **first_load = NULL;
struct elf_segment_map **last_load = NULL;
bfd_boolean moved_headers = FALSE;
while (*m != NULL)
{
struct elf_segment_map *seg = *m;
if (seg->p_type == PT_LOAD)
{
/* First, we're just finding the earliest PT_LOAD.
By the normal rules, this will be the lowest-addressed one.
We only have anything interesting to do if it's executable. */
last_load = m;
if (first_load == NULL)
{
if (!segment_executable (*m))
return TRUE;
first_load = m;
}
/* Now that we've noted the first PT_LOAD, we're looking for
the first non-executable PT_LOAD with a nonempty p_filesz. */
else if (!moved_headers
&& segment_nonexecutable_and_has_contents (seg))
{
/* This is the one we were looking for!
First, clear the flags on previous segments that
say they include the file header and phdrs. */
struct elf_segment_map *prevseg;
for (prevseg = *first_load;
prevseg != seg;
prevseg = prevseg->next)
if (prevseg->p_type == PT_LOAD)
{
prevseg->includes_filehdr = 0;
prevseg->includes_phdrs = 0;
}
/* This segment will include those headers instead. */
seg->includes_filehdr = 1;
seg->includes_phdrs = 1;
moved_headers = TRUE;
}
}
m = &seg->next;
}
if (first_load != last_load && moved_headers)
{
/* Now swap the first and last PT_LOAD segments'
positions in segment_map. */
struct elf_segment_map *first = *first_load;
struct elf_segment_map *last = *last_load;
*first_load = first->next;
first->next = last->next;
last->next = first;
}
return TRUE;
}
/* After nacl_modify_segment_map has done its work, the file layout has
been done as we wanted. But the PT_LOAD phdrs are no longer in the
proper order for the ELF rule that they must appear in ascending address
order. So find the two segments we swapped before, and swap them back. */
bfd_boolean
nacl_modify_program_headers (bfd *abfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
struct elf_segment_map **m = &elf_tdata (abfd)->segment_map;
Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
Elf_Internal_Phdr *p = phdr;
/* Find the PT_LOAD that contains the headers (should be the first). */
while (*m != NULL)
{
if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr)
break;
m = &(*m)->next;
++p;
}
if (*m != NULL)
{
struct elf_segment_map **first_load_seg = m;
Elf_Internal_Phdr *first_load_phdr = p;
struct elf_segment_map **next_load_seg = NULL;
Elf_Internal_Phdr *next_load_phdr = NULL;
/* Now move past that first one and find the PT_LOAD that should be
before it by address order. */
m = &(*m)->next;
++p;
while ((*m) != NULL)
{
if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr)
{
next_load_seg = m;
next_load_phdr = p;
break;
}
m = &(*m)->next;
++p;
}
/* Swap their positions in the segment_map back to how they used to be.
The phdrs have already been set up by now, so we have to slide up
the earlier ones to insert the one that should be first. */
if (next_load_seg != NULL)
{
Elf_Internal_Phdr move_phdr;
struct elf_segment_map *first_seg = *first_load_seg;
struct elf_segment_map *next_seg = *next_load_seg;
struct elf_segment_map *first_next = first_seg->next;
struct elf_segment_map *next_next = next_seg->next;
first_seg->next = next_next;
*first_load_seg = next_seg;
next_seg->next = first_next;
*next_load_seg = first_seg;
move_phdr = *next_load_phdr;
memmove (first_load_phdr + 1, first_load_phdr,
(next_load_phdr - first_load_phdr) * sizeof move_phdr);
*first_load_phdr = move_phdr;
}
}
return TRUE;
}