aboutsummaryrefslogtreecommitdiff
path: root/bfd/seclet.c
diff options
context:
space:
mode:
authorSteve Chamberlain <sac@cygnus>1992-01-24 22:44:51 +0000
committerSteve Chamberlain <sac@cygnus>1992-01-24 22:44:51 +0000
commite98e6ec1117b83defce2b1ccce6fd4ec3877bbfb (patch)
tree9fa72011ba39d8612b300def67a0816d7dcac02b /bfd/seclet.c
parent95a876f3fa09e75e129afbf4fab65f634f3c5ec2 (diff)
downloadgdb-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.c370
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;
+ }
+
+}