+ /* We only run this relaxation once. It might work to run it
+ multiple times, but it hasn't been tested. */
+ *again = FALSE;
+
+ if (reloc_size)
+ {
+ long reloc_count;
+
+ reloc_vector = bfd_malloc ((bfd_size_type) reloc_size);
+ if (reloc_vector == NULL && reloc_size != 0)
+ goto error_return;
+
+ /* Get the relocs and think about them. */
+ reloc_count =
+ bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
+ _bfd_generic_link_get_symbols (input_bfd));
+ if (reloc_count < 0)
+ goto error_return;
+ if (reloc_count > 0)
+ {
+ arelent **parent;
+
+ for (parent = reloc_vector; *parent; parent++)
+ {
+ arelent *r = *parent;
+
+ switch (r->howto->type)
+ {
+ case ALIGNER:
+ /* An alignment reloc. */
+ shrink = aligncode (abfd, input_section, r, shrink);
+ break;
+ case ABS32CODE:
+ /* A 32bit reloc in an addressing mode. */
+ shrink = abs32code (input_bfd, input_section, r, shrink,
+ link_info);
+ break;
+ case ABS32CODE_SHRUNK:
+ shrink += 4;
+ break;
+ }
+ }
+ }
+ }
+ input_section->size -= shrink;
+
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return TRUE;
+ error_return:
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return FALSE;
+}
+
+static bfd_byte *
+b_out_bfd_get_relocated_section_contents (bfd *output_bfd,
+ struct bfd_link_info *link_info,
+ struct bfd_link_order *link_order,
+ bfd_byte *data,
+ bfd_boolean relocatable,
+ asymbol **symbols)
+{
+ /* Get enough memory to hold the stuff. */
+ bfd *input_bfd = link_order->u.indirect.section->owner;
+ asection *input_section = link_order->u.indirect.section;
+ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+ arelent **reloc_vector = NULL;
+ long reloc_count;
+
+ if (reloc_size < 0)
+ goto error_return;
+
+ /* If producing relocatable output, don't bother to relax. */
+ if (relocatable)
+ return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
+ link_order,
+ data, relocatable,
+ symbols);
+
+ reloc_vector = bfd_malloc ((bfd_size_type) reloc_size);
+ if (reloc_vector == NULL && reloc_size != 0)
+ goto error_return;
+
+ /* Read in the section. */
+ BFD_ASSERT (bfd_get_section_contents (input_bfd,
+ input_section,
+ data,
+ (bfd_vma) 0,
+ input_section->size));
+
+ reloc_count = bfd_canonicalize_reloc (input_bfd,
+ input_section,
+ reloc_vector,
+ symbols);
+ if (reloc_count < 0)
+ goto error_return;
+ if (reloc_count > 0)
+ {
+ 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 < link_order->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. */
+ BFD_ASSERT (reloc->address >= src_address);
+ run = reloc->address - src_address;
+ parent++;
+ }
+ else
+ run = link_order->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 ABS32CODE:
+ calljx_callback (input_bfd, link_info, reloc,
+ src_address + data, dst_address + data,
+ input_section);
+ src_address += 4;
+ dst_address += 4;
+ break;
+ case ABS32:
+ bfd_put_32 (input_bfd,
+ (bfd_get_32 (input_bfd, data + src_address)
+ + get_value (reloc, link_info, input_section)),
+ data + dst_address);
+ src_address += 4;
+ dst_address += 4;
+ break;
+ case CALLJ:
+ callj_callback (input_bfd, link_info, reloc, data,
+ src_address, dst_address, input_section,
+ FALSE);
+ src_address += 4;
+ dst_address += 4;
+ break;
+ case ALIGNDONE:
+ BFD_ASSERT (reloc->addend >= src_address);
+ BFD_ASSERT ((bfd_vma) reloc->addend
+ <= input_section->size);
+ src_address = reloc->addend;
+ dst_address = ((dst_address + reloc->howto->size)
+ & ~reloc->howto->size);
+ break;
+ case ABS32CODE_SHRUNK:
+ /* This used to be a callx, but we've found out that a
+ callj will reach, so do the right thing. */
+ callj_callback (input_bfd, link_info, reloc, data,
+ src_address + 4, dst_address, input_section,
+ TRUE);
+ dst_address += 4;
+ src_address += 8;
+ break;
+ case PCREL24:
+ {
+ long int word = bfd_get_32 (input_bfd,
+ data + src_address);
+ bfd_vma value;
+
+ value = get_value (reloc, link_info, input_section);
+ word = ((word & ~BAL_MASK)
+ | (((word & BAL_MASK)
+ + value
+ - output_addr (input_section)
+ + reloc->addend)
+ & BAL_MASK));
+
+ bfd_put_32 (input_bfd, (bfd_vma) word, data + dst_address);
+ dst_address += 4;
+ src_address += 4;
+
+ }
+ break;
+ case PCREL13:
+ {
+ long int word = bfd_get_32 (input_bfd,
+ data + src_address);
+ bfd_vma value;
+
+ value = get_value (reloc, link_info, input_section);
+ word = ((word & ~PCREL13_MASK)
+ | (((word & PCREL13_MASK)
+ + value
+ + reloc->addend
+ - output_addr (input_section))
+ & PCREL13_MASK));
+
+ bfd_put_32 (input_bfd, (bfd_vma) word, data + dst_address);
+ dst_address += 4;
+ src_address += 4;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ }
+ }
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return data;
+ error_return:
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return NULL;
+}
+\f