X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fldwrite.c;h=b56119a39ac124ae410cca6183afc2371c2d3fdb;hb=50e05050cddfd84925e0dc7a09228cb15035f4fa;hp=de37d4012fc29e10d04c33d3a9b1ece928f8bddf;hpb=e59e0390a5157c591ad7d9d6d7102e1cc5bc5f04;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldwrite.c b/ld/ldwrite.c index de37d4012f..b56119a39a 100644 --- a/ld/ldwrite.c +++ b/ld/ldwrite.c @@ -1,449 +1,530 @@ -fooo +/* ldwrite.c -- write out the linked file + Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998 + Free Software Foundation, Inc. + Written by Steve Chamberlain sac@cygnus.com -/* Copyright (C) 1991 Free Software Foundation, Inc. - This file is part of GLD, the Gnu Linker. -GLD is free software; you can redistribute it and/or modify +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 1, or (at your option) -any later version. +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. -GLD is distributed in the hope that it will be useful, +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 GLD; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* - * $Id$ - * - * $Log$ - * Revision 1.2 1991/03/22 22:31:37 steve - * *** empty log message *** - * - * Revision 1.1.1.1 1991/03/21 21:29:05 gumby - * Back from Intel with Steve - * - * Revision 1.1 1991/03/21 21:29:04 gumby - * Initial revision - * - * Revision 1.2 1991/03/15 18:45:55 rich - * foo - * - * Revision 1.1 1991/03/13 00:48:37 chrisb - * Initial revision - * - * Revision 1.7 1991/03/10 19:15:03 sac - * Took out the abort() which had been put in the wrong place - * Updated the version #. - * - * Revision 1.6 1991/03/10 09:31:41 rich - * Modified Files: - * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c - * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h - * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c - * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c - * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h - * - * As of this round of changes, ld now builds on all hosts of (Intel960) - * interest and copy passes my copy test on big endian hosts again. - * - * Revision 1.5 1991/03/09 03:25:08 sac - * Added support for LONG, SHORT and BYTE keywords in scripts - * - * Revision 1.4 1991/03/06 21:59:34 sac - * Completed G++ support - * - * Revision 1.3 1991/03/06 02:29:52 sac - * Added support for partial linking. - * - * Revision 1.2 1991/02/22 17:15:11 sac - * Added RCS keywords and copyrights - * -*/ - -/* - This module writes out the final image by reading sections from the - input files, relocating them and writing them out - - There are two main paths through this module, one for normal - operation and one for partial linking. - - During normal operation, raw section data is read along with the - associated relocation information, the relocation info applied and - the section data written out on a section by section basis. - - When partially linking, all the relocation records are read to work - out how big the output relocation vector will be. Then raw data is - read, relocated and written section by section. - - Written by Steve Chamberlain steve@cygnus.com - -*/ +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 "sysdep.h" +#include "bfdlink.h" +#include "libiberty.h" -#include "ldlang.h" #include "ld.h" +#include "ldexp.h" +#include "ldlang.h" #include "ldwrite.h" #include "ldmisc.h" -#include "ldsym.h" -#include "ldgram.tab.h" - - +#include "ldgram.h" +#include "ldmain.h" -char *ldmalloc(); -/* Static vars for do_warnings and subroutines of it */ -int list_unresolved_refs; /* List unresolved refs */ -int list_warning_symbols; /* List warning syms */ -int list_multiple_defs; /* List multiple definitions */ -extern int errno; -extern char *sys_errlist[]; +static void build_link_order PARAMS ((lang_statement_union_type *)); +static asection *clone_section PARAMS ((bfd *, asection *, int *)); +static void split_sections PARAMS ((bfd *, struct bfd_link_info *)); -extern unsigned int undefined_global_sym_count; +/* Build link_order structures for the BFD linker. */ -extern bfd *output_bfd; - -extern struct lang_output_section_statement_struct * create_object_symbols; - -extern char lprefix; - -#ifdef __STDC__ -void lang_for_each_statement(void (*func)()); -#else /* __STDC__ */ -void lang_for_each_statement(); -#endif /* __STDC__ */ - -extern size_t largest_section; -ld_config_type config; +static void +build_link_order (statement) + lang_statement_union_type *statement; +{ + switch (statement->header.type) + { + case lang_data_statement_enum: + { + asection *output_section; + struct bfd_link_order *link_order; + bfd_vma value; + boolean big_endian = false; + + output_section = statement->data_statement.output_section; + ASSERT (output_section->owner == output_bfd); + + link_order = bfd_new_link_order (output_bfd, output_section); + if (link_order == NULL) + einfo (_("%P%F: bfd_new_link_order failed\n")); + + link_order->type = bfd_data_link_order; + link_order->offset = statement->data_statement.output_vma; + link_order->u.data.contents = (bfd_byte *) xmalloc (QUAD_SIZE); + + value = statement->data_statement.value; + + /* If the endianness of the output BFD is not known, then we + base the endianness of the data on the first input file. + By convention, the bfd_put routines for an unknown + endianness are big endian, so we must swap here if the + input file is little endian. */ + if (bfd_big_endian (output_bfd)) + big_endian = true; + else if (bfd_little_endian (output_bfd)) + big_endian = false; + else + { + boolean swap; + + swap = false; + if (command_line.endian == ENDIAN_BIG) + big_endian = true; + else if (command_line.endian == ENDIAN_LITTLE) + { + big_endian = false; + swap = true; + } + else if (command_line.endian == ENDIAN_UNSET) + { + big_endian = true; + { + LANG_FOR_EACH_INPUT_STATEMENT (s) + { + if (s->the_bfd != NULL) + { + if (bfd_little_endian (s->the_bfd)) + { + big_endian = false; + swap = true; + } + break; + } + } + } + } -extern unsigned int global_symbol_count; + if (swap) + { + bfd_byte buffer[8]; + + switch (statement->data_statement.type) + { + case QUAD: + case SQUAD: + if (sizeof (bfd_vma) >= QUAD_SIZE) + { + bfd_putl64 (value, buffer); + value = bfd_getb64 (buffer); + break; + } + /* Fall through. */ + case LONG: + bfd_putl32 (value, buffer); + value = bfd_getb32 (buffer); + break; + case SHORT: + bfd_putl16 (value, buffer); + value = bfd_getb16 (buffer); + break; + case BYTE: + break; + default: + abort (); + } + } + } -boolean trace_files; + ASSERT (output_section->owner == output_bfd); + switch (statement->data_statement.type) + { + case QUAD: + case SQUAD: + if (sizeof (bfd_vma) >= QUAD_SIZE) + bfd_put_64 (output_bfd, value, link_order->u.data.contents); + else + { + bfd_vma high; + + if (statement->data_statement.type == QUAD) + high = 0; + else if ((value & 0x80000000) == 0) + high = 0; + else + high = (bfd_vma) -1; + bfd_put_32 (output_bfd, high, + (link_order->u.data.contents + + (big_endian ? 0 : 4))); + bfd_put_32 (output_bfd, value, + (link_order->u.data.contents + + (big_endian ? 4 : 0))); + } + link_order->size = QUAD_SIZE; + break; + case LONG: + bfd_put_32 (output_bfd, value, link_order->u.data.contents); + link_order->size = LONG_SIZE; + break; + case SHORT: + bfd_put_16 (output_bfd, value, link_order->u.data.contents); + link_order->size = SHORT_SIZE; + break; + case BYTE: + bfd_put_8 (output_bfd, value, link_order->u.data.contents); + link_order->size = BYTE_SIZE; + break; + default: + abort (); + } + } + break; + + case lang_reloc_statement_enum: + { + lang_reloc_statement_type *rs; + asection *output_section; + struct bfd_link_order *link_order; + + rs = &statement->reloc_statement; + + output_section = rs->output_section; + ASSERT (output_section->owner == output_bfd); + + link_order = bfd_new_link_order (output_bfd, output_section); + if (link_order == NULL) + einfo (_("%P%F: bfd_new_link_order failed\n")); + + link_order->offset = rs->output_vma; + link_order->size = bfd_get_reloc_size (rs->howto); + + link_order->u.reloc.p = + ((struct bfd_link_order_reloc *) + xmalloc (sizeof (struct bfd_link_order_reloc))); + + link_order->u.reloc.p->reloc = rs->reloc; + link_order->u.reloc.p->addend = rs->addend_value; + + if (rs->name == NULL) + { + link_order->type = bfd_section_reloc_link_order; + if (rs->section->owner == output_bfd) + link_order->u.reloc.p->u.section = rs->section; + else + { + link_order->u.reloc.p->u.section = rs->section->output_section; + link_order->u.reloc.p->addend += rs->section->output_offset; + } + } + else + { + link_order->type = bfd_symbol_reloc_link_order; + link_order->u.reloc.p->u.name = rs->name; + } + } + break; -static void perform_relocation(input_bfd, - input_section, - data, - symbols) -bfd *input_bfd; -asection *input_section; -void *data; -asymbol **symbols; -{ - static asymbol *error_symbol = (asymbol *)NULL; - static unsigned int error_count = 0; -#define MAX_ERRORS_IN_A_ROW 5 - size_t reloc_size = get_reloc_upper_bound(input_bfd, input_section); - - arelent **reloc_vector = (arelent **)ldmalloc(reloc_size); - arelent **parent; - bfd *ob = output_bfd; - asection *os = input_section->output_section; - if (config.relocateable_output == false) ob = (bfd *)NULL; - - if (bfd_canonicalize_reloc(input_bfd, - input_section, - reloc_vector, - symbols) ) - { - for (parent = reloc_vector; *parent; parent++) + case lang_input_section_enum: + /* Create a new link_order in the output section with this + attached */ + if (statement->input_section.ifile->just_syms_flag == false) { + asection *i = statement->input_section.section; + asection *output_section = i->output_section; - bfd_reloc_status_enum_type r= - bfd_perform_relocation(input_bfd, - *parent, - data, - input_section, - ob); - - if (r == bfd_reloc_ok) { - if (ob != (bfd *)NULL) { - /* A parital link, so keep the relocs */ - os->orelocation[os->reloc_count] = *parent; - os->reloc_count++; - } - } - else + ASSERT (output_section->owner == output_bfd); + + if ((output_section->flags & SEC_HAS_CONTENTS) != 0) { - asymbol *s; - arelent *p = *parent; + struct bfd_link_order *link_order; - if (ob != (bfd *)NULL) { - /* A parital link, so keep the relocs */ - os->orelocation[os->reloc_count] = *parent; - os->reloc_count++; - } + link_order = bfd_new_link_order (output_bfd, output_section); - if (p->sym_ptr_ptr != (asymbol **)NULL) { - s = *(p->sym_ptr_ptr); - } - else { - s = (asymbol *)NULL; - } - switch (r) + if (i->flags & SEC_NEVER_LOAD) { - case bfd_reloc_undefined: - /* We remember the symbol, and never print more than - a reasonable number of them in a row */ - if (s == error_symbol) { - error_count++; - } - else { - error_count = 0; - error_symbol = s; - } - if (error_count < MAX_ERRORS_IN_A_ROW) { - info("%C: undefined reference to `%T'\n", - input_bfd, - input_section, - symbols, - (*parent)->address, - s); - config.make_executable = false; - } - else if (error_count == MAX_ERRORS_IN_A_ROW) { - info("%C: more undefined references to `%T' follow\n", - input_bfd, - input_section, - symbols, - (*parent)->address, - s); - } - else { - /* Don't print any more */ - } - break; - case bfd_reloc_dangerous: - info("%B: relocation may be wrong `%T'\n", - input_bfd, - s); - break; - case bfd_reloc_outofrange: - info("%B:%s relocation address out of range %T (%x)\n", - input_bfd, - input_section->name, - s, - p->address); - break; - case bfd_reloc_overflow: - info("%B:%s relocation overflow in %T reloc type %d\n", - input_bfd, - input_section->name, - s, - p->howto->type); - break; - default: - info("%F%B: relocation error, symbol `%T'\n", - input_bfd, - s); - break; + /* We've got a never load section inside one which + is going to be output, we'll change it into a + fill link_order */ + link_order->type = bfd_fill_link_order; + link_order->u.fill.value = 0; + } + else + { + link_order->type = bfd_indirect_link_order; + link_order->u.indirect.section = i; + ASSERT (i->output_section == output_section); } + if (i->_cooked_size) + link_order->size = i->_cooked_size; + else + link_order->size = bfd_get_section_size_before_reloc (i); + link_order->offset = i->output_offset; } } + break; + + case lang_padding_statement_enum: + /* Make a new link_order with the right filler */ + { + asection *output_section; + struct bfd_link_order *link_order; + + output_section = statement->padding_statement.output_section; + ASSERT (statement->padding_statement.output_section->owner + == output_bfd); + if ((output_section->flags & SEC_HAS_CONTENTS) != 0) + { + link_order = bfd_new_link_order (output_bfd, output_section); + link_order->type = bfd_fill_link_order; + link_order->size = statement->padding_statement.size; + link_order->offset = statement->padding_statement.output_offset; + link_order->u.fill.value = statement->padding_statement.fill; + } + } + break; + + default: + /* All the other ones fall through */ + break; } - free((char *)reloc_vector); } +/* Call BFD to write out the linked file. */ +/**********************************************************************/ - -void *data_area; - -static void -copy_and_relocate(statement) -lang_statement_union_type *statement; +/* Wander around the input sections, make sure that + we'll never try and create an output section with more relocs + than will fit.. Do this by always assuming the worst case, and + creating new output sections with all the right bits */ +#define TESTIT 1 +static asection * +clone_section (abfd, s, count) + bfd *abfd; + asection *s; + int *count; { - switch (statement->header.type) { - case lang_fill_statement_enum: +#define SSIZE 8 + char sname[SSIZE]; /* ?? find the name for this size */ + asection *n; + struct bfd_link_hash_entry *h; + /* Invent a section name - use first five + chars of base section name and a digit suffix */ + do { -#if 0 - bfd_byte play_area[SHORT_SIZE]; unsigned int i; - bfd_putshort(output_bfd, statement->fill_statement.fill, play_area); - /* Write out all entire shorts */ - for (i = 0; - i < statement->fill_statement.size - SHORT_SIZE + 1; - i+= SHORT_SIZE) - { - bfd_set_section_contents(output_bfd, - statement->fill_statement.output_section, - play_area, - statement->data_statement.output_offset +i, - SHORT_SIZE); + char b[6]; + for (i = 0; i < sizeof (b) - 1 && s->name[i]; i++) + b[i] = s->name[i]; + b[i] = 0; + sprintf (sname, "%s%d", b, (*count)++); + } + while (bfd_get_section_by_name (abfd, sname)); + + n = bfd_make_section_anyway (abfd, xstrdup (sname)); + + /* Create a symbol of the same name */ + + h = bfd_link_hash_lookup (link_info.hash, + sname, true, true, false); + h->type = bfd_link_hash_defined; + h->u.def.value = 0; + h->u.def.section = n ; + + + n->flags = s->flags; + n->vma = s->vma; + n->user_set_vma = s->user_set_vma; + n->lma = s->lma; + n->_cooked_size = 0; + n->_raw_size = 0; + n->output_offset = s->output_offset; + n->output_section = n; + n->orelocation = 0; + n->reloc_count = 0; + n->alignment_power = s->alignment_power; + return n; +} +#if TESTING +static void +ds (s) + asection *s; +{ + struct bfd_link_order *l = s->link_order_head; + printf ("vma %x size %x\n", s->vma, s->_raw_size); + while (l) + { + if (l->type == bfd_indirect_link_order) + { + printf ("%8x %s\n", l->offset, l->u.indirect.section->owner->filename); } - - /* Now write any remaining byte */ - if (i < statement->fill_statement.size) + else { - bfd_set_section_contents(output_bfd, - statement->fill_statement.output_section, - play_area, - statement->data_statement.output_offset +i, - 1); - + printf (_("%8x something else\n"), l->offset); } -#endif + l = l->next; } - break; - case lang_data_statement_enum: - { - bfd_vma value = statement->data_statement.value; - bfd_byte play_area[LONG_SIZE]; - unsigned int size; - switch (statement->data_statement.type) { - case LONG: - bfd_putlong(output_bfd, value, play_area); - size = LONG_SIZE; - break; - case SHORT: - bfd_putshort(output_bfd, value, play_area); - size = SHORT_SIZE; - break; - case BYTE: - bfd_putchar(output_bfd, value, play_area); - size = BYTE_SIZE; - break; - } - - bfd_set_section_contents(output_bfd, - statement->data_statement.output_section, - play_area, - statement->data_statement.output_vma, - size); - - - + printf ("\n"); +} +dump (s, a1, a2) + char *s; + asection *a1; + asection *a2; +{ + printf ("%s\n", s); + ds (a1); + ds (a2); +} +static void +sanity_check (abfd) + bfd *abfd; +{ + asection *s; + for (s = abfd->sections; s; s = s->next) + { + struct bfd_link_order *p; + bfd_vma prev = 0; + for (p = s->link_order_head; p; p = p->next) + { + if (p->offset > 100000) + abort (); + if (p->offset < prev) + abort (); + prev = p->offset; + } } - break; - case lang_input_section_enum: +} +#else +#define sanity_check(a) +#define dump(a, b, c) +#endif + +static void +split_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection *original_sec; + int nsecs = abfd->section_count; + sanity_check (abfd); + /* look through all the original sections */ + for (original_sec = abfd->sections; + original_sec && nsecs; + original_sec = original_sec->next, nsecs--) { - - asection *i = statement->input_section.section; - asection *output_section = i->output_section; - lang_input_statement_type *ifile = statement->input_section.ifile; - bfd *inbfd = ifile->the_bfd; - if (output_section->flags & SEC_LOAD && i->size != 0) + boolean first = true; + int count = 0; + int lines = 0; + int relocs = 0; + struct bfd_link_order **pp; + bfd_vma vma = original_sec->vma; + bfd_vma shift_offset = 0; + asection *cursor = original_sec; + + /* count up the relocations and line entries to see if + anything would be too big to fit */ + for (pp = &(cursor->link_order_head); *pp; pp = &((*pp)->next)) { - if(bfd_get_section_contents(inbfd, - i, - data_area, - 0L, - i->size) == false) + struct bfd_link_order *p = *pp; + int thislines = 0; + int thisrelocs = 0; + if (p->type == bfd_indirect_link_order) { - info("%F%B error reading section contents %E\n", - inbfd); - } - perform_relocation (inbfd, i, data_area, ifile->asymbols); + asection *sec; + sec = p->u.indirect.section; + + if (info->strip == strip_none + || info->strip == strip_some) + thislines = sec->lineno_count; + + if (info->relocateable) + thisrelocs = sec->reloc_count; - if(bfd_set_section_contents(output_bfd, - output_section, - data_area, - (file_ptr)i->output_offset, - i->size) == false) - { - info("%F%B error writing section contents of %E\n", - output_bfd); } + else if (info->relocateable + && (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order)) + thisrelocs++; + + if (! first + && (thisrelocs + relocs > config.split_by_reloc + || thislines + lines > config.split_by_reloc + || config.split_by_file)) + { + /* create a new section and put this link order and the + following link orders into it */ + struct bfd_link_order *l = p; + asection *n = clone_section (abfd, cursor, &count); + *pp = NULL; /* Snip off link orders from old section */ + n->link_order_head = l; /* attach to new section */ + pp = &n->link_order_head; - } - } - break; + /* change the size of the original section and + update the vma of the new one */ - default: - /* All the other ones fall through */ - ; + dump ("before snip", cursor, n); - } -} + n->_raw_size = cursor->_raw_size - l->offset; + cursor->_raw_size = l->offset; -void -write_norel() -{ - /* Output the text and data segments, relocating as we go. */ - lang_for_each_statement(copy_and_relocate); -} + vma += cursor->_raw_size; + n->lma = n->vma = vma; + shift_offset = l->offset; -static void read_relocs(abfd, section, symbols) -bfd *abfd; -asection *section; -asymbol **symbols; -{ - /* Work out the output section ascociated with this input section */ - asection *output_section = section->output_section; - - size_t reloc_size = get_reloc_upper_bound(abfd, section); - arelent **reloc_vector = (arelent **)ldmalloc(reloc_size); - - if (bfd_canonicalize_reloc(abfd, - section, - reloc_vector, - symbols)) { - output_section->reloc_count += section->reloc_count; - } -} + /* run down the chain and change the output section to + the right one, update the offsets too */ + while (l) + { + l->offset -= shift_offset; + if (l->type == bfd_indirect_link_order) + { + l->u.indirect.section->output_section = n; + l->u.indirect.section->output_offset = l->offset; + } + l = l->next; + } + dump ("after snip", cursor, n); + cursor = n; + relocs = thisrelocs; + lines = thislines; + } + else + { + relocs += thisrelocs; + lines += thislines; + } -static void -write_rel() -{ - /* - Run through each section of each file and work work out the total - number of relocation records which will finally be in each output - section - */ - - LANG_FOR_EACH_INPUT_SECTION - (statement, abfd, section, - (read_relocs(abfd, section, statement->asymbols))); - - - - /* - Now run though all the output sections and allocate the space for - all the relocations - */ - LANG_FOR_EACH_OUTPUT_SECTION - (section, - (section->orelocation = - (arelent **)ldmalloc((size_t)(sizeof(arelent **)* - section->reloc_count)), - section->reloc_count = 0, - section->flags |= SEC_HAS_CONTENTS)); - - - /* - Copy the data, relocating as we go - */ - lang_for_each_statement(copy_and_relocate); + first = false; + } + } + sanity_check (abfd); } - +/**********************************************************************/ void ldwrite () { - data_area = (void*) ldmalloc(largest_section); - if (config.relocateable_output == true) + /* Reset error indicator, which can typically something like invalid + format from openning up the .o files */ + bfd_set_error (bfd_error_no_error); + lang_for_each_statement (build_link_order); + + if (config.split_by_reloc || config.split_by_file) + split_sections (output_bfd, &link_info); + if (!bfd_final_link (output_bfd, &link_info)) { - write_rel(); + /* If there was an error recorded, print it out. Otherwise assume + an appropriate error message like unknown symbol was printed + out. */ + + if (bfd_get_error () != bfd_error_no_error) + einfo (_("%F%P: final link failed: %E\n"), output_bfd); + else + xexit(1); } - else - { - write_norel(); - } - free(data_area); - /* Output the symbol table (both globals and locals). */ - ldsym_write (); - } -