diff options
author | Steve Chamberlain <sac@cygnus> | 1992-01-24 22:44:51 +0000 |
---|---|---|
committer | Steve Chamberlain <sac@cygnus> | 1992-01-24 22:44:51 +0000 |
commit | e98e6ec1117b83defce2b1ccce6fd4ec3877bbfb (patch) | |
tree | 9fa72011ba39d8612b300def67a0816d7dcac02b /bfd/seclet.c | |
parent | 95a876f3fa09e75e129afbf4fab65f634f3c5ec2 (diff) | |
download | gdb-e98e6ec1117b83defce2b1ccce6fd4ec3877bbfb.zip gdb-e98e6ec1117b83defce2b1ccce6fd4ec3877bbfb.tar.gz gdb-e98e6ec1117b83defce2b1ccce6fd4ec3877bbfb.tar.bz2 |
Uses the new small reloc type now.
Currently self hosts on sun4 and sun3
Diffstat (limited to 'bfd/seclet.c')
-rw-r--r-- | bfd/seclet.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/bfd/seclet.c b/bfd/seclet.c new file mode 100644 index 0000000..4088f0e --- /dev/null +++ b/bfd/seclet.c @@ -0,0 +1,370 @@ +/* This module is part of BFD */ + + +/* The intention is that one day, all the code which uses sections + will change and use seclets instead - maybe seglet would have been + a better name.. + + Anyway, a seclet contains enough info to be able to describe an + area of output memory in one go. + + The only description so far catered for is that of the + <<bfd_indirect_seclet>>, which is a select which points to a + <<section>> and the <<asymbols>> associated with the section, so + that relocation can be done when needed. + + One day there will be more types - they will at least migrate from + the linker's data structures - also there could be extra stuff, + like a bss seclet, which descibes a lump of memory as containing + zeros compactly, without the horrible SEC_* flag cruft. + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +#include "coff/internal.h" +bfd_seclet_type * +DEFUN(bfd_new_seclet,(abfd, section), + bfd *abfd AND + asection *section) +{ + bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type)); + if (section->seclets_tail != (bfd_seclet_type *)NULL) { + section->seclets_tail->next = n; + } + else + { + section->seclets_head = n; + } + section->seclets_tail = n; + + return n; + +} + + + + +#define MAX_ERRORS_IN_A_ROW 10 +extern bfd_error_vector_type bfd_error_vector; +bfd_vma +DEFUN(get_value,(reloc, seclet), + arelent *reloc AND + bfd_seclet_type *seclet) +{ + bfd_vma value; + if (reloc->sym_ptr_ptr) + { + asymbol *symbol = *(reloc->sym_ptr_ptr); + + + /* A symbol holds a pointer to a section, and an offset from the + base of the section. To relocate, we find where the section will + live in the output and add that in */ + + if (symbol->section == (asection *)NULL) + { + /* Ouch, this is an undefined symbol.. */ + bfd_error_vector.undefined_symbol(reloc, seclet); + value = symbol->value; + } + else + { + value = symbol->value + + symbol->section->output_offset + + symbol->section->output_section->vma; + } + } + + else + { + value = 0; + } + + /* Add the value contained in the relocation */ + value += (short)((reloc->addend) & 0xffff); + + return value; + + +} + +static char * +DEFUN(foo_bfd_get_relocated_section_contents,(seclet), + bfd_seclet_type *seclet) + +{ + asymbol **symbols = 0; + extern bfd *output_bfd; + bfd *abfd; + + /* Get enough memory to hold the stuff */ + bfd *input_bfd = seclet->u.indirect.section->owner; + asection *input_section = seclet->u.indirect.section; + + char *data = malloc(input_section->_raw_size); + char *dst = data; + char *prev_dst = data; + unsigned int gap = 0; + + bfd_size_type reloc_size = bfd_get_reloc_upper_bound(input_bfd, + input_section); + arelent **reloc_vector = (arelent **)ldmalloc(reloc_size); + abfd = output_bfd; + + /* read in the section */ + bfd_get_section_contents(input_bfd, + input_section, + data, + 0, + input_section->_raw_size); + + + if (bfd_canonicalize_reloc(input_bfd, + input_section, + reloc_vector, + seclet->u.indirect.symbols) ) + { + arelent **parent = reloc_vector; + arelent *reloc ; + + + + unsigned int dst_address = 0; + unsigned int src_address = 0; + unsigned int run; + unsigned int idx; + + /* Find how long a run we can do */ + while (dst_address < seclet->size) + { + + reloc = *parent; + if (reloc) + { + /* Note that the relaxing didn't tie up the addresses in the + relocation, so we use the original address to work out the + run of non-relocated data */ + run = reloc->address - src_address; + parent++; + + } + else + { + run = seclet->size - dst_address; + } + /* Copy the bytes */ + for (idx = 0; idx < run; idx++) + { + data[dst_address++] = data[src_address++]; + } + + /* Now do the relocation */ + + if (reloc) + { + switch (reloc->howto->type) + { + case R_JMP2: + /* Speciial relaxed type */ + { + bfd_vma dot = seclet->offset + dst_address + seclet->u.indirect.section->output_section->vma; + int gap = get_value(reloc,seclet)-dot-1; + if ((gap & ~0xff ) != 0 &&((gap & 0xff00)!= 0xff00)) abort(); + + bfd_put_8(abfd,gap, data+dst_address); + + switch (data[dst_address-1]) + { + + case 0x5e: + /* jsr -> bsr */ + bfd_put_8(abfd, 0x55, data+dst_address-1); + break; + case 0x5a: + /* jmp ->bra */ + bfd_put_8(abfd, 0x40, data+dst_address-1); + break; + + default: + abort(); + + } + + + + + dst_address++; + src_address+=3; + + break; + } + + + case R_MOVB2: + /* Special relaxed type, there will be a gap between where we + get stuff from and where we put stuff to now + + for a mov.b @aa:16 -> mov.b @aa:8 + opcode 0x6a 0x0y offset + -> 0x2y off + */ + if (data[dst_address-1] != 0x6a) + abort(); + switch (data[dst_address] & 0xf0) + { + case 0x00: + /* Src is memory */ + data[dst_address-1] = (data[src_address] & 0xf) | 0x20; + break; + case 0x80: + /* Src is reg */ + data[dst_address-1] = (data[src_address] & 0xf) | 0x30; + break; + default: + abort(); + } + + /* the offset must fit ! after all, what was all the relaxing + about ? */ + + bfd_put_8(abfd, get_value(reloc, seclet), data + dst_address); + + /* Note the magic - src goes up by two bytes, but dst by only + one */ + dst_address+=1; + src_address+=3; + + break; + /* PCrel 8 bits */ + case R_PCRBYTE: + { + bfd_vma dot = seclet->offset + dst_address + seclet->u.indirect.section->output_section->vma; + int gap = get_value(reloc,seclet)-dot; + if (gap > 127 || gap < -128) + { + bfd_error_vector.reloc_value_truncated(reloc, seclet); + } + + bfd_put_8(abfd,gap, data+dst_address); + dst_address++; + src_address++; + + break; + } + + case R_RELBYTE: + { + unsigned int gap =get_value(reloc,seclet); + if (gap > 256) + { + bfd_error_vector.reloc_value_truncated(reloc, seclet); + } + + bfd_put_8(abfd, gap, data+dst_address); + dst_address+=1; + src_address+=1; + + + } + break; + case R_JMP1: + /* A relword which would have like to have been a pcrel */ + case R_MOVB1: + /* A relword which would like to have been modified but + didn't make it */ + case R_RELWORD: + bfd_put_16(abfd, get_value(reloc,seclet), data+dst_address); + dst_address+=2; + src_address+=2; + break; + + default: + abort(); + } + } + } + } + free((char *)reloc_vector); + return data; + +} + +void +DEFUN(rel,(abfd, seclet, output_section), + bfd *abfd AND + bfd_seclet_type *seclet AND + asection *output_section) +{ + bfd_byte *data; + if (output_section->flags & SEC_HAS_CONTENTS ) + { + + data = bfd_get_relocated_section_contents(abfd, seclet); + + if(bfd_set_section_contents(abfd, + output_section, + data, + seclet->offset, + seclet->size) == false) + { + abort(); + } + +} + + + + + +} + +void +DEFUN(seclet_dump_seclet,(abfd, seclet, section), + bfd *abfd AND + bfd_seclet_type *seclet AND + asection *section) +{ + switch (seclet->type) + { + + case bfd_indirect_seclet: + /* The contents of this section come from another one somewhere + else */ + rel(abfd, seclet, section); + + + break; + + default: + abort(); + } + + + +} + +void +DEFUN(seclet_dump,(abfd), + bfd *abfd) +{ + /* Write all the seclets on the bfd out, relocate etc according to the + rules */ + + asection *o = abfd->sections; + while (o != (asection *)NULL) + { + bfd_seclet_type *p = o->seclets_head; + while (p != (bfd_seclet_type *)NULL) + { + seclet_dump_seclet(abfd, p, o); + p = p ->next; + } + + o = o->next; + } + +} |