diff options
author | Richard Henderson <rth@redhat.com> | 1999-05-03 07:29:06 +0000 |
---|---|---|
committer | Richard Henderson <rth@redhat.com> | 1999-05-03 07:29:06 +0000 |
commit | 860acaebec6b57ce27e244cc02a58e6651a4b6c3 (patch) | |
tree | eff5420756a4bd56b40b74c2b828b261f327610b /bfd/elflink.c | |
parent | f9c53ad2d7cb541cbe821d645b90437ac063e5db (diff) | |
download | gdb-860acaebec6b57ce27e244cc02a58e6651a4b6c3.tar.gz |
Initial revision
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c new file mode 100644 index 00000000000..dc0b0428c60 --- /dev/null +++ b/bfd/elflink.c @@ -0,0 +1,433 @@ +/* ELF linking support for BFD. + Copyright 1995, 1996, 1997 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 2 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 "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "elf-bfd.h" + +boolean +_bfd_elf_create_got_section (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + int ptralign; + + /* This function may be called more than once. */ + if (bfd_get_section_by_name (abfd, ".got") != NULL) + return true; + + switch (bed->s->arch_size) + { + case 32: ptralign = 2; break; + case 64: ptralign = 3; break; + default: abort(); + } + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + s = bfd_make_section (abfd, ".got"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return false; + + if (bed->want_got_plt) + { + s = bfd_make_section (abfd, ".got.plt"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return false; + } + + /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got + (or .got.plt) section. We don't do this in the linker script + because we don't want to define the symbol if we are not creating + a global offset table. */ + h = NULL; + if (!(_bfd_generic_link_add_one_symbol + (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, + bed->got_symbol_offset, (const char *) NULL, false, + bed->collect, (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + elf_hash_table (info)->hgot = h; + + /* The first bit of the global offset table is the header. */ + s->_raw_size += bed->got_header_size + bed->got_symbol_offset; + + return true; +} + + +/* Create dynamic sections when linking against a dynamic object. */ + +boolean +_bfd_elf_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags, pltflags; + register asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + int ptralign; + + switch (bed->s->arch_size) + { + case 32: ptralign = 2; break; + case 64: ptralign = 3; break; + default: abort(); + } + + /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and + .rel[a].bss sections. */ + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + pltflags = flags; + pltflags |= SEC_CODE; + if (bed->plt_not_loaded) + pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); + if (bed->plt_readonly) + pltflags |= SEC_READONLY; + + s = bfd_make_section (abfd, ".plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, pltflags) + || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) + return false; + + if (bed->want_plt_sym) + { + /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the + .plt section. */ + struct elf_link_hash_entry *h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + + s = bfd_make_section (abfd, bed->use_rela_p ? ".rela.plt" : ".rel.plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, ptralign)) + return false; + + if (! _bfd_elf_create_got_section (abfd, info)) + return false; + + /* The .dynbss section is a place to put symbols which are defined + by dynamic objects, are referenced by regular objects, and are + not functions. We must allocate space for them in the process + image and use a R_*_COPY reloc to tell the dynamic linker to + initialize them at run time. The linker script puts the .dynbss + section into the .bss section of the final image. */ + s = bfd_make_section (abfd, ".dynbss"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) + return false; + + /* The .rel[a].bss section holds copy relocs. This section is not + normally needed. We need to create it here, though, so that the + linker will map it to an output section. We can't just create it + only if we need it, because we will not know whether we need it + until we have seen all the input files, and the first time the + main linker code calls BFD after examining all the input files + (size_dynamic_sections) the input sections have already been + mapped to the output sections. If the section turns out not to + be needed, we can discard it later. We will never need this + section when generating a shared object, since they do not use + copy relocs. */ + if (! info->shared) + { + s = bfd_make_section (abfd, bed->use_rela_p ? ".rela.bss" : ".rel.bss"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, ptralign)) + return false; + } + + return true; +} + + +/* Record a new dynamic symbol. We record the dynamic symbols as we + read the input files, since we need to have a list of all of them + before we can determine the final sizes of the output sections. + Note that we may actually call this function even though we are not + going to output any dynamic symbols; in some cases we know that a + symbol should be in the dynamic symbol table, but only if there is + one. */ + +boolean +_bfd_elf_link_record_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + if (h->dynindx == -1) + { + struct bfd_strtab_hash *dynstr; + char *p, *alc; + const char *name; + boolean copy; + bfd_size_type indx; + + h->dynindx = elf_hash_table (info)->dynsymcount; + ++elf_hash_table (info)->dynsymcount; + + dynstr = elf_hash_table (info)->dynstr; + if (dynstr == NULL) + { + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init (); + if (dynstr == NULL) + return false; + } + + /* We don't put any version information in the dynamic string + table. */ + name = h->root.root.string; + p = strchr (name, ELF_VER_CHR); + if (p == NULL) + { + alc = NULL; + copy = false; + } + else + { + alc = bfd_malloc (p - name + 1); + if (alc == NULL) + return false; + strncpy (alc, name, p - name); + alc[p - name] = '\0'; + name = alc; + copy = true; + } + + indx = _bfd_stringtab_add (dynstr, name, true, copy); + + if (alc != NULL) + free (alc); + + if (indx == (bfd_size_type) -1) + return false; + h->dynstr_index = indx; + } + + return true; +} + +/* Create a special linker section, or return a pointer to a linker section already created */ + +elf_linker_section_t * +_bfd_elf_create_linker_section (abfd, info, which, defaults) + bfd *abfd; + struct bfd_link_info *info; + enum elf_linker_section_enum which; + elf_linker_section_t *defaults; +{ + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *lsect; + + /* Record the first bfd section that needs the special section */ + if (!dynobj) + dynobj = elf_hash_table (info)->dynobj = abfd; + + /* If this is the first time, create the section */ + lsect = elf_linker_section (dynobj, which); + if (!lsect) + { + asection *s; + + lsect = (elf_linker_section_t *) + bfd_alloc (dynobj, sizeof (elf_linker_section_t)); + + *lsect = *defaults; + elf_linker_section (dynobj, which) = lsect; + lsect->which = which; + lsect->hole_written_p = false; + + /* See if the sections already exist */ + lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name); + if (!s || (s->flags & defaults->flags) != defaults->flags) + { + lsect->section = s = bfd_make_section_anyway (dynobj, lsect->name); + + if (s == NULL) + return (elf_linker_section_t *)0; + + bfd_set_section_flags (dynobj, s, defaults->flags); + bfd_set_section_alignment (dynobj, s, lsect->alignment); + } + else if (bfd_get_section_alignment (dynobj, s) < lsect->alignment) + bfd_set_section_alignment (dynobj, s, lsect->alignment); + + s->_raw_size = align_power (s->_raw_size, lsect->alignment); + + /* Is there a hole we have to provide? If so check whether the segment is + too big already */ + if (lsect->hole_size) + { + lsect->hole_offset = s->_raw_size; + s->_raw_size += lsect->hole_size; + if (lsect->hole_offset > lsect->max_hole_offset) + { + (*_bfd_error_handler) (_("%s: Section %s is already to large to put hole of %ld bytes in"), + bfd_get_filename (abfd), + lsect->name, + (long)lsect->hole_size); + + bfd_set_error (bfd_error_bad_value); + return (elf_linker_section_t *)0; + } + } + +#ifdef DEBUG + fprintf (stderr, "Creating section %s, current size = %ld\n", + lsect->name, (long)s->_raw_size); +#endif + + if (lsect->sym_name) + { + struct elf_link_hash_entry *h = NULL; +#ifdef DEBUG + fprintf (stderr, "Adding %s to section %s\n", + lsect->sym_name, + lsect->name); +#endif + h = (struct elf_link_hash_entry *) + bfd_link_hash_lookup (info->hash, lsect->sym_name, false, false, false); + + if ((h == NULL || h->root.type == bfd_link_hash_undefined) + && !(_bfd_generic_link_add_one_symbol (info, + abfd, + lsect->sym_name, + BSF_GLOBAL, + s, + ((lsect->hole_size) + ? s->_raw_size - lsect->hole_size + lsect->sym_offset + : lsect->sym_offset), + (const char *) NULL, + false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return (elf_linker_section_t *)0; + + if ((defaults->which != LINKER_SECTION_SDATA) + && (defaults->which != LINKER_SECTION_SDATA2)) + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; + + h->type = STT_OBJECT; + lsect->sym_hash = h; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return (elf_linker_section_t *)0; + } + } + +#if 0 + /* This does not make sense. The sections which may exist in the + object file have nothing to do with the sections we want to + create. */ + + /* Find the related sections if they have been created */ + if (lsect->bss_name && !lsect->bss_section) + lsect->bss_section = bfd_get_section_by_name (dynobj, lsect->bss_name); + + if (lsect->rel_name && !lsect->rel_section) + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); +#endif + + return lsect; +} + + +/* Find a linker generated pointer with a given addend and type. */ + +elf_linker_section_pointers_t * +_bfd_elf_find_pointer_linker_section (linker_pointers, addend, which) + elf_linker_section_pointers_t *linker_pointers; + bfd_signed_vma addend; + elf_linker_section_enum_t which; +{ + for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) + { + if (which == linker_pointers->which && addend == linker_pointers->addend) + return linker_pointers; + } + + return (elf_linker_section_pointers_t *)0; +} + + +/* Make the .rela section corresponding to the generated linker section. */ + +boolean +_bfd_elf_make_linker_section_rela (dynobj, lsect, alignment) + bfd *dynobj; + elf_linker_section_t *lsect; + int alignment; +{ + if (lsect->rel_section) + return true; + + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL) + { + lsect->rel_section = bfd_make_section (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL + || ! bfd_set_section_flags (dynobj, + lsect->rel_section, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, lsect->rel_section, alignment)) + return false; + } + + return true; +} |