static void build_link_order (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; bfd_boolean big_endian = FALSE; output_section = statement->data_statement.output_section; ASSERT (output_section->owner == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); link_order->type = bfd_data_link_order; link_order->offset = statement->data_statement.output_offset; 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 (link_info.output_bfd)) big_endian = TRUE; else if (bfd_little_endian (link_info.output_bfd)) big_endian = FALSE; else { bfd_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; } } } } 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 (); } } } ASSERT (output_section->owner == link_info.output_bfd); switch (statement->data_statement.type) { case QUAD: case SQUAD: if (sizeof (bfd_vma) >= QUAD_SIZE) bfd_put_64 (link_info.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 (link_info.output_bfd, high, (link_order->u.data.contents + (big_endian ? 0 : 4))); bfd_put_32 (link_info.output_bfd, value, (link_order->u.data.contents + (big_endian ? 4 : 0))); } link_order->size = QUAD_SIZE; break; case LONG: bfd_put_32 (link_info.output_bfd, value, link_order->u.data.contents); link_order->size = LONG_SIZE; break; case SHORT: bfd_put_16 (link_info.output_bfd, value, link_order->u.data.contents); link_order->size = SHORT_SIZE; break; case BYTE: bfd_put_8 (link_info.output_bfd, value, link_order->u.data.contents); link_order->size = BYTE_SIZE; break; default: abort (); } link_order->u.data.size = link_order->size; } 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 == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); link_order->offset = rs->output_offset; 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 == link_info.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; case lang_input_section_enum: { /* Create a new link_order in the output section with this attached */ asection *i = statement->input_section.section; if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS && (i->flags & SEC_EXCLUDE) == 0) { asection *output_section = i->output_section; struct bfd_link_order *link_order; ASSERT (output_section->owner == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); if ((i->flags & SEC_NEVER_LOAD) != 0 && (i->flags & SEC_DEBUGGING) == 0) { /* We've got a never load section inside one which is going to be output, we'll change it into a fill. */ link_order->type = bfd_data_link_order; link_order->u.data.contents = (unsigned char *) ""; link_order->u.data.size = 1; } else { link_order->type = bfd_indirect_link_order; link_order->u.indirect.section = i; ASSERT (i->output_section == output_section); } link_order->size = i->size; 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 == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); link_order->type = bfd_data_link_order; link_order->size = statement->padding_statement.size; link_order->offset = statement->padding_statement.output_offset; link_order->u.data.contents = statement->padding_statement.fill->data; link_order->u.data.size = statement->padding_statement.fill->size; } break; default: /* All the other ones fall through */ break; }
static void extra_case (bfd *in_abfd, struct bfd_link_info *link_info, struct bfd_link_order *link_order, arelent *reloc, bfd_byte *data, unsigned int *src_ptr, unsigned int *dst_ptr) { asection * input_section = link_order->u.indirect.section; switch (reloc->howto->type) { case R_IMM8: bfd_put_8 (in_abfd, bfd_coff_reloc16_get_value (reloc, link_info, input_section), data + *dst_ptr); (*dst_ptr) += 1; (*src_ptr) += 1; break; case R_IMM32: /* If no flags are set, assume immediate value. */ if (! (*reloc->sym_ptr_ptr)->section->flags) { bfd_put_32 (in_abfd, bfd_coff_reloc16_get_value (reloc, link_info, input_section), data + *dst_ptr); } else { bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, input_section); /* Addresses are 23 bit, and the layout of those in a 32-bit value is as follows: 1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA (A - address bits, x - ignore). */ dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000; bfd_put_32 (in_abfd, dst, data + *dst_ptr); } (*dst_ptr) += 4; (*src_ptr) += 4; break; case R_IMM4L: bfd_put_8 (in_abfd, ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0) | (0x0f & bfd_coff_reloc16_get_value (reloc, link_info, input_section))), data + *dst_ptr); (*dst_ptr) += 1; (*src_ptr) += 1; break; case R_IMM16: bfd_put_16 (in_abfd, bfd_coff_reloc16_get_value (reloc, link_info, input_section), data + *dst_ptr); (*dst_ptr) += 2; (*src_ptr) += 2; break; case R_JR: { bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, input_section); bfd_vma dot = (link_order->offset + *dst_ptr + input_section->output_section->vma); /* -1L, since we are in the odd byte of the word, and the pc has been * incremented: */ ptrdiff_t gap = ((ptrdiff_t)(dst - dot) - 1L); if (gap & 1L) abort(); gap /= 2L; if ((gap > 128L) || (gap < -128L)) { if (!((*link_info->callbacks->reloc_overflow) (link_info, NULL, bfd_asymbol_name(*reloc->sym_ptr_ptr), reloc->howto->name, reloc->addend, input_section->owner, input_section, reloc->address))) abort(); } bfd_put_8(in_abfd, gap, (data + *dst_ptr)); (*dst_ptr)++; (*src_ptr)++; break; } case R_DISP7: { bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, input_section); bfd_vma dot = (link_order->offset + *dst_ptr + input_section->output_section->vma); /* -1L, since we are in the odd byte of the word, and the pc has been * incremented: */ ptrdiff_t gap = ((ptrdiff_t)(dst - dot) - 1L); if (gap & 1L) abort(); gap /= 2L; if ((gap > 0L) || (gap < -127L)) { if (!((*link_info->callbacks->reloc_overflow) (link_info, NULL, bfd_asymbol_name(*reloc->sym_ptr_ptr), reloc->howto->name, reloc->addend, input_section->owner, input_section, reloc->address))) abort(); } bfd_put_8(in_abfd, (bfd_get_8(in_abfd, data + *dst_ptr) & 0x80) + (-gap & 0x7f), (data + *dst_ptr)); (*dst_ptr)++; (*src_ptr)++; break; } case R_CALLR: { bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, input_section); bfd_vma dot = (link_order->offset + *dst_ptr + input_section->output_section->vma); ptrdiff_t gap = ((ptrdiff_t)(dst - dot) - 2L); if (gap & 1L) abort(); if ((gap > 4096L) || (gap < -4095L)) { if (!((*link_info->callbacks->reloc_overflow) (link_info, NULL, bfd_asymbol_name(*reloc->sym_ptr_ptr), reloc->howto->name, reloc->addend, input_section->owner, input_section, reloc->address))) abort(); } gap /= 2L; bfd_put_16(in_abfd, ((bfd_get_16(in_abfd, (data + *dst_ptr)) & 0xf000) | (-gap & 0x0fff)), (data + *dst_ptr)); (*dst_ptr) += 2; (*src_ptr) += 2; break; } case R_REL16: { bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, input_section); bfd_vma dot = (link_order->offset + *dst_ptr + input_section->output_section->vma); ptrdiff_t gap = ((ptrdiff_t)(dst - dot) - 2L); if ((gap > 32767L) || (gap < -32768L)) { if (!((*link_info->callbacks->reloc_overflow) (link_info, NULL, bfd_asymbol_name(*reloc->sym_ptr_ptr), reloc->howto->name, reloc->addend, input_section->owner, input_section, reloc->address))) abort(); } bfd_put_16(in_abfd, (bfd_vma)gap, (data + *dst_ptr)); (*dst_ptr) += 2; (*src_ptr) += 2; break; } default: abort(); } }