diff options
author | Steve Chamberlain <sac@cygnus> | 1992-01-24 22:34:34 +0000 |
---|---|---|
committer | Steve Chamberlain <sac@cygnus> | 1992-01-24 22:34:34 +0000 |
commit | 2e2bf962db00b2e23a222687e4bc3c5971c645b7 (patch) | |
tree | 0eceb10d2d00f8f32ad14ea539129ee894d7f1e9 /ld/relax.c | |
parent | 2cbe4c5f9e97dff6786352e1867c3c6afd383258 (diff) | |
download | gdb-2e2bf962db00b2e23a222687e4bc3c5971c645b7.zip gdb-2e2bf962db00b2e23a222687e4bc3c5971c645b7.tar.gz gdb-2e2bf962db00b2e23a222687e4bc3c5971c645b7.tar.bz2 |
* Makefile.in: added relax, also made three stage go through a
partial link stage.
* relax.c : added
* config.h: if GNU960 defined, then default emulation mode is
GLD960
* ldexp.h, ldexp.c: map to file hooks
* ldlang.c: map to file hooks
* ldgram.y: added -Map -relax
* ldlex.l: added -relax, -Map
* ldmain.c: open map file
* ldmisc.c: support for map file
* ldwrite.c: new relax magic
Diffstat (limited to 'ld/relax.c')
-rw-r--r-- | ld/relax.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/ld/relax.c b/ld/relax.c new file mode 100644 index 0000000..6db5590 --- /dev/null +++ b/ld/relax.c @@ -0,0 +1,299 @@ + + +/* + +new age linking + + +Tie together all the interseting blocks + +*/ + + +#include "bfd.h" +#include "../bfd/seclet.h" +#include "coff/internal.h" +#include "sysdep.h" + +#include "ldlang.h" +#include "ld.h" +#include "ldwrite.h" +#include "ldmisc.h" +#include "ldsym.h" +#include "ldgram.h" + +static void +DEFUN(build_it,(statement), + lang_statement_union_type *statement) +{ + switch (statement->header.type) { + case lang_fill_statement_enum: + { +#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); + + } + + /* Now write any remaining byte */ + if (i < statement->fill_statement.size) + { + bfd_set_section_contents(output_bfd, + statement->fill_statement.output_section, + play_area, + statement->data_statement.output_offset +i, + 1); + + } +#endif + } + break; + case lang_data_statement_enum: + { +abort(); + +#if 0 + bfd_vma value = statement->data_statement.value; + bfd_byte play_area[LONG_SIZE]; + unsigned int size = 0; + switch (statement->data_statement.type) { + case LONG: + bfd_put_32(output_bfd, value, play_area); + size = LONG_SIZE; + break; + case SHORT: + bfd_put_16(output_bfd, value, play_area); + size = SHORT_SIZE; + break; + case BYTE: + bfd_put_8(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); + + +#endif + + } + break; + case lang_input_section_enum: + { + /* Create a new seclet in the output section with this + attached */ + + asection *i = statement->input_section.section; + + asection *output_section = i->output_section; + + bfd_seclet_type *seclet = bfd_new_seclet(output_section->owner,output_section); + + seclet->type = bfd_indirect_seclet; + seclet->u.indirect.section = i; + seclet->u.indirect.symbols = statement->input_section.ifile->asymbols; + seclet->size = bfd_get_section_size_before_reloc(i); + seclet->offset = i->output_offset; + seclet->next = 0; + + } + break; + + default: + /* All the other ones fall through */ + ; + + } + + + +} + + +void +DEFUN(write_relaxnorel,(output_bfd), + bfd *output_bfd) +{ +/* Tie up all the statements to generate an output bfd structure which + bfd can mull over */ + + + lang_for_each_statement(build_it); + + seclet_dump(output_bfd); + +} + + + +static void +DEFUN(perform_slip,(s, slip, input_section, value), + asymbol **s AND + unsigned int slip AND + asection *input_section AND + bfd_vma value) +{ + + /* Find all symbols past this point, and make them know + what's happened */ + while (*s) + { + asymbol *p = *s; + if (p->section == input_section) + { + /* This was pointing into this section, so mangle it */ + if (p->value > value) + { + p->value -=2; + } + } + s++; + + } +} +static int +DEFUN(movb1,(input_section, symbols, r, shrink), + asection *input_section AND + asymbol **symbols AND + arelent *r AND + unsigned int shrink) +{ + + + bfd_vma value = get_value(r, input_section); + + if (value >= 0xff00) + { + + /* Change the reloc type from 16bit, possible 8 to 8bit + possible 16 */ + r->howto = r->howto + 1; + /* The place to relc moves back by one */ + r->address -=1; + + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + perform_slip(symbols, 2, input_section, r->address - shrink +1); + + + } + return shrink; +} + +static int +DEFUN(jmp1,(input_section, symbols, r, shrink), + asection *input_section AND + asymbol **symbols AND + arelent *r AND + unsigned int shrink) +{ + + + bfd_vma value = get_value(r, 0); + + bfd_vma dot = input_section->output_section->vma + + input_section->output_offset + r->address; + bfd_vma gap; + + /* See if the address we're looking at within 127 bytes of where + we are, if so then we can use a small branch rather than the + jump we were going to */ + + gap = value - (dot - shrink); + + + if (-120 < (long)gap && (long)gap < 120 ) + { + + /* Change the reloc type from 16bit, possible 8 to 8bit + possible 16 */ + r->howto = r->howto + 1; + /* The place to relc moves back by one */ + r->address -=1; + + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + perform_slip(symbols, 2, input_section, r->address-shrink +1); + + + } + return shrink; +} + + +/* See if we can change the size of this section by shrinking the + relocations in it. If this happens, then we'll have to renumber the + symbols in it, and shift around the data too. + */ +boolean +DEFUN(relax_section,(this_ptr), + lang_statement_union_type **this_ptr) +{ + + lang_input_section_type *is = &((*this_ptr)->input_section); + asection *i = is->section; + + + /* Get enough memory to hold the stuff */ + bfd *input_bfd = i->owner; + asection *input_section = i; + int shrink = 0 ; + int new = 0; + + bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd, + input_section); + arelent **reloc_vector = (arelent **)ldmalloc(reloc_size); + + /* Get the relocs and think about them */ + if (bfd_canonicalize_reloc(input_bfd, + input_section, + reloc_vector, + is->ifile->asymbols) ) + { + arelent **parent; + asymbol **symbols = is->ifile->asymbols; + for (parent = reloc_vector; *parent; parent++) + { + arelent *r = *parent; + switch (r->howto->type) { + case R_MOVB2: + case R_JMP2: + + shrink+=2; + break; + + case R_MOVB1: + shrink = movb1(input_section, symbols, r, shrink); + new = 1; + + break; + case R_JMP1: + shrink = jmp1(input_section, symbols, r, shrink); + new = 1; + + break; + } + } + + } + input_section->_cooked_size -= shrink; + free((char *)reloc_vector); + return new; + +} + |