summaryrefslogtreecommitdiff
path: root/bfd/elf32-arm.c
diff options
context:
space:
mode:
authorMark Shinwell <shinwell@codesourcery.com>2006-06-15 11:03:01 +0000
committerMark Shinwell <shinwell@codesourcery.com>2006-06-15 11:03:01 +0000
commit0a30e5cab6fed1e62fbe4d8ef5323ea1abcec23e (patch)
tree044d740ebcc07b10921d67f90b5b2f18d93f7dfe /bfd/elf32-arm.c
parente5b7198be2d75fe67d64c65fd74ab1a503cd299e (diff)
downloadgdb-0a30e5cab6fed1e62fbe4d8ef5323ea1abcec23e.tar.gz
* include/elf/arm.h: Correct names of R_ARM_LDC_G{0,1,2}
to R_ARM_LDC_SB_G{0,1,2} respectively. bfd/ * bfd-in2.h: Regenerate. * elf32-arm.c (R_ARM_ALU_PC_G0_NC, R_ARM_ALU_PC_G0, R_ARM_ALU_PC_G1_NC, R_ARM_ALU_PC_G1, R_ARM_ALU_PC_G2, R_ARM_LDR_PC_G1, R_ARM_LDR_PC_G2, R_ARM_LDRS_PC_G0, R_ARM_LDRS_PC_G1, R_ARM_LDRS_PC_G2, R_ARM_LDC_PC_G0, R_ARM_LDC_PC_G1, R_ARM_LDC_PC_G2, R_ARM_ALU_SB_G0_NC, R_ARM_ALU_SB_G0, R_ARM_ALU_SB_G1_NC, R_ARM_ALU_SB_G1, R_ARM_ALU_SB_G2, R_ARM_LDR_SB_G0, R_ARM_LDR_SB_G1, R_ARM_LDR_SB_G2, R_ARM_LDRS_SB_G0, R_ARM_LDRS_SB_G1, R_ARM_LDRS_SB_G2, R_ARM_LDC_SB_G0, R_ARM_LDC_SB_G1, R_ARM_LDC_SB_G2): New relocation types. (R_ARM_PC13): Rename to AAELF name R_ARM_LDR_PC_G0 and adjust HOWTO entry to be consistent with R_ARM_LDR_PC_G1 and friends. (elf32_arm_howto_table_3): Delete; contents merged into elf32_arm_howto_table_2. (elf32_arm_howto_from_type): Adjust correspondingly. (elf32_arm_reloc_map): Extend with the above relocations. (calculate_group_reloc_mask): New function. (identify_add_or_sub): New function. (elf32_arm_final_link_relocate): Support for the above relocations. * reloc.c: Add enumeration entries for BFD_RELOC_ARM_... codes to correspond to the above relocations. gas/ * config/tc-arm.c (enum parse_operand_result): New. (struct group_reloc_table_entry): New. (enum group_reloc_type): New. (group_reloc_table): New array. (find_group_reloc_table_entry): New function. (parse_shifter_operand_group_reloc): New function. (parse_address_main): New function, incorporating code from the old parse_address function. To be used via... (parse_address): wrapper for parse_address_main; and (parse_address_group_reloc): new function, likewise. (enum operand_parse_code): New codes OP_SHG, OP_ADDRGLDR, OP_ADDRGLDRS, OP_ADDRGLDC. (parse_operands): Support for these new operand codes. New macro po_misc_or_fail_no_backtrack. (encode_arm_cp_address): Preserve group relocations. (insns): Modify to use the above operand codes where group relocations are permitted. (md_apply_fix): Handle the group relocations ALU_PC_G0_NC through LDC_SB_G2. (tc_gen_reloc): Likewise. (arm_force_relocation): Leave group relocations for the linker. (arm_fix_adjustable): Likewise. gas/testsuite/ * gas/arm/group-reloc-alu.d: New test. * gas/arm/group-reloc-alu-encoding-bad.d: New test. * gas/arm/group-reloc-alu-encoding-bad.l: New test. * gas/arm/group-reloc-alu-encoding-bad.s: New test. * gas/arm/group-reloc-alu-parsing-bad.d: New test. * gas/arm/group-reloc-alu-parsing-bad.l: New test. * gas/arm/group-reloc-alu-parsing-bad.s: New test. * gas/arm/group-reloc-alu.s: New test. * gas/arm/group-reloc-ldc.d: New test. * gas/arm/group-reloc-ldc-encoding-bad.d: New test. * gas/arm/group-reloc-ldc-encoding-bad.l: New test. * gas/arm/group-reloc-ldc-encoding-bad.s: New test. * gas/arm/group-reloc-ldc-parsing-bad.d: New test. * gas/arm/group-reloc-ldc-parsing-bad.l: New test. * gas/arm/group-reloc-ldc-parsing-bad.s: New test. * gas/arm/group-reloc-ldc.s: New test. * gas/arm/group-reloc-ldr.d: New test. * gas/arm/group-reloc-ldr-encoding-bad.d: New test. * gas/arm/group-reloc-ldr-encoding-bad.l: New test. * gas/arm/group-reloc-ldr-encoding-bad.s: New test. * gas/arm/group-reloc-ldr-parsing-bad.d: New test. * gas/arm/group-reloc-ldr-parsing-bad.l: New test. * gas/arm/group-reloc-ldr-parsing-bad.s: New test. * gas/arm/group-reloc-ldr.s: New test. * gas/arm/group-reloc-ldrs.d: New test. * gas/arm/group-reloc-ldrs-encoding-bad.d: New test. * gas/arm/group-reloc-ldrs-encoding-bad.l: New test. * gas/arm/group-reloc-ldrs-encoding-bad.s: New test. * gas/arm/group-reloc-ldrs-parsing-bad.d: New test. * gas/arm/group-reloc-ldrs-parsing-bad.l: New test. * gas/arm/group-reloc-ldrs-parsing-bad.s: New test. * gas/arm/group-reloc-ldrs.s: New test. ld/testsuite/ * ld-arm/group-relocs-alu-bad.d: New test. * ld-arm/group-relocs-alu-bad.s: New test. * ld-arm/group-relocs.d: New test. * ld-arm/group-relocs-ldc-bad.d: New test. * ld-arm/group-relocs-ldc-bad.s: New test. * ld-arm/group-relocs-ldr-bad.d: New test. * ld-arm/group-relocs-ldr-bad.s: New test. * ld-arm/group-relocs-ldrs-bad.d: New test. * ld-arm/group-relocs-ldrs-bad.s: New test. * ld-arm/group-relocs.s: New test. * ld-arm/arm-elf.exp: Wire in new tests.
Diffstat (limited to 'bfd/elf32-arm.c')
-rw-r--r--bfd/elf32-arm.c897
1 files changed, 878 insertions, 19 deletions
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index ae8ef8f70ac..639a6105ab9 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -130,19 +130,19 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
TRUE), /* pcrel_offset */
/* 8 bit absolute - R_ARM_LDR_PC_G0 in AAELF */
- HOWTO (R_ARM_PC13, /* type */
+ HOWTO (R_ARM_LDR_PC_G0, /* type */
0, /* rightshift */
0, /* size (0 = byte, 1 = short, 2 = long) */
- 8, /* bitsize */
- FALSE, /* pc_relative */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield,/* complain_on_overflow */
+ complain_overflow_dont,/* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- "R_ARM_PC13", /* name */
+ "R_ARM_LDR_PC_G0", /* name */
FALSE, /* partial_inplace */
- 0x000000ff, /* src_mask */
- 0x000000ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
/* 16 bit absolute */
HOWTO (R_ARM_ABS16, /* type */
@@ -884,13 +884,389 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
-};
-/* Relocations 57 .. 83 are the "group relocations" which we do not
- support. */
+ /* Group relocations. */
+
+ HOWTO (R_ARM_ALU_PC_G0_NC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_PC_G0_NC", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_PC_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_PC_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_PC_G1_NC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_PC_G1_NC", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_PC_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_PC_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_PC_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_PC_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDR_PC_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDR_PC_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDR_PC_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDR_PC_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDRS_PC_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDRS_PC_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDRS_PC_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDRS_PC_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDRS_PC_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDRS_PC_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDC_PC_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDC_PC_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDC_PC_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDC_PC_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDC_PC_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDC_PC_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_SB_G0_NC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_SB_G0_NC", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_SB_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_SB_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_SB_G1_NC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_SB_G1_NC", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_SB_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_SB_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_ALU_SB_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_ALU_SB_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDR_SB_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDR_SB_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDR_SB_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDR_SB_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDR_SB_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDR_SB_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDRS_SB_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDRS_SB_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDRS_SB_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDRS_SB_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDRS_SB_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDRS_SB_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDC_SB_G0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDC_SB_G0", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDC_SB_G1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDC_SB_G1", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_ARM_LDC_SB_G2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_LDC_SB_G2", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* End of group relocations. */
-static reloc_howto_type elf32_arm_howto_table_2[] =
-{
HOWTO (R_ARM_MOVW_BREL_NC, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
@@ -1230,7 +1606,7 @@ static reloc_howto_type elf32_arm_howto_table_2[] =
249-255 extended, currently unused, relocations: */
-static reloc_howto_type elf32_arm_howto_table_3[4] =
+static reloc_howto_type elf32_arm_howto_table_2[4] =
{
HOWTO (R_ARM_RREL32, /* type */
0, /* rightshift */
@@ -1295,13 +1671,9 @@ elf32_arm_howto_from_type (unsigned int r_type)
if (r_type < NUM_ELEM (elf32_arm_howto_table_1))
return &elf32_arm_howto_table_1[r_type];
- if (r_type >= R_ARM_MOVW_BREL_NC
- && r_type < R_ARM_MOVW_BREL_NC + NUM_ELEM (elf32_arm_howto_table_2))
- return &elf32_arm_howto_table_2[r_type - R_ARM_MOVW_BREL_NC];
-
if (r_type >= R_ARM_RREL32
&& r_type < R_ARM_RREL32 + NUM_ELEM (elf32_arm_howto_table_2))
- return &elf32_arm_howto_table_3[r_type - R_ARM_RREL32];
+ return &elf32_arm_howto_table_2[r_type - R_ARM_RREL32];
return NULL;
}
@@ -1374,6 +1746,34 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
{BFD_RELOC_ARM_THUMB_MOVT, R_ARM_THM_MOVT_ABS},
{BFD_RELOC_ARM_THUMB_MOVW_PCREL, R_ARM_THM_MOVW_PREL_NC},
{BFD_RELOC_ARM_THUMB_MOVT_PCREL, R_ARM_THM_MOVT_PREL},
+ {BFD_RELOC_ARM_ALU_PC_G0_NC, R_ARM_ALU_PC_G0_NC},
+ {BFD_RELOC_ARM_ALU_PC_G0, R_ARM_ALU_PC_G0},
+ {BFD_RELOC_ARM_ALU_PC_G1_NC, R_ARM_ALU_PC_G1_NC},
+ {BFD_RELOC_ARM_ALU_PC_G1, R_ARM_ALU_PC_G1},
+ {BFD_RELOC_ARM_ALU_PC_G2, R_ARM_ALU_PC_G2},
+ {BFD_RELOC_ARM_LDR_PC_G0, R_ARM_LDR_PC_G0},
+ {BFD_RELOC_ARM_LDR_PC_G1, R_ARM_LDR_PC_G1},
+ {BFD_RELOC_ARM_LDR_PC_G2, R_ARM_LDR_PC_G2},
+ {BFD_RELOC_ARM_LDRS_PC_G0, R_ARM_LDRS_PC_G0},
+ {BFD_RELOC_ARM_LDRS_PC_G1, R_ARM_LDRS_PC_G1},
+ {BFD_RELOC_ARM_LDRS_PC_G2, R_ARM_LDRS_PC_G2},
+ {BFD_RELOC_ARM_LDC_PC_G0, R_ARM_LDC_PC_G0},
+ {BFD_RELOC_ARM_LDC_PC_G1, R_ARM_LDC_PC_G1},
+ {BFD_RELOC_ARM_LDC_PC_G2, R_ARM_LDC_PC_G2},
+ {BFD_RELOC_ARM_ALU_SB_G0_NC, R_ARM_ALU_SB_G0_NC},
+ {BFD_RELOC_ARM_ALU_SB_G0, R_ARM_ALU_SB_G0},
+ {BFD_RELOC_ARM_ALU_SB_G1_NC, R_ARM_ALU_SB_G1_NC},
+ {BFD_RELOC_ARM_ALU_SB_G1, R_ARM_ALU_SB_G1},
+ {BFD_RELOC_ARM_ALU_SB_G2, R_ARM_ALU_SB_G2},
+ {BFD_RELOC_ARM_LDR_SB_G0, R_ARM_LDR_SB_G0},
+ {BFD_RELOC_ARM_LDR_SB_G1, R_ARM_LDR_SB_G1},
+ {BFD_RELOC_ARM_LDR_SB_G2, R_ARM_LDR_SB_G2},
+ {BFD_RELOC_ARM_LDRS_SB_G0, R_ARM_LDRS_SB_G0},
+ {BFD_RELOC_ARM_LDRS_SB_G1, R_ARM_LDRS_SB_G1},
+ {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2},
+ {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0},
+ {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1},
+ {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}
};
static reloc_howto_type *
@@ -2964,6 +3364,74 @@ elf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value)
return bfd_reloc_ok;
}
+/* For a given value of n, calculate the value of G_n as required to
+ deal with group relocations. We return it in the form of an
+ encoded constant-and-rotation, together with the final residual. If n is
+ specified as less than zero, then final_residual is filled with the
+ input value and no further action is performed. */
+
+static bfd_vma
+calculate_group_reloc_mask (bfd_vma value, int n, bfd_vma *final_residual)
+{
+ int current_n;
+ bfd_vma g_n;
+ bfd_vma encoded_g_n = 0;
+ bfd_vma residual = value; /* Also known as Y_n. */
+
+ for (current_n = 0; current_n <= n; current_n++)
+ {
+ int shift;
+
+ /* Calculate which part of the value to mask. */
+ if (residual == 0)
+ shift = 0;
+ else
+ {
+ int msb;
+
+ /* Determine the most significant bit in the residual and
+ align the resulting value to a 2-bit boundary. */
+ for (msb = 30; msb >= 0; msb -= 2)
+ if (residual & (3 << msb))
+ break;
+
+ /* The desired shift is now (msb - 6), or zero, whichever
+ is the greater. */
+ shift = msb - 6;
+ if (shift < 0)
+ shift = 0;
+ }
+
+ /* Calculate g_n in 32-bit as well as encoded constant+rotation form. */
+ g_n = residual & (0xff << shift);
+ encoded_g_n = (g_n >> shift)
+ | ((g_n <= 0xff ? 0 : (32 - shift) / 2) << 8);
+
+ /* Calculate the residual for the next time around. */
+ residual &= ~g_n;
+ }
+
+ *final_residual = residual;
+
+ return encoded_g_n;
+}
+
+/* Given an ARM instruction, determine whether it is an ADD or a SUB.
+ Returns 1 if it is an ADD, -1 if it is a SUB, and 0 otherwise. */
+static int
+identify_add_or_sub(bfd_vma insn)
+{
+ int opcode = insn & 0x1e00000;
+
+ if (opcode == 1 << 23) /* ADD */
+ return 1;
+
+ if (opcode == 1 << 22) /* SUB */
+ return -1;
+
+ return 0;
+}
+
/* Perform a relocation as part of a final link. */
static bfd_reloc_status_type
@@ -4187,6 +4655,397 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
}
return bfd_reloc_ok;
+ case R_ARM_ALU_PC_G0_NC:
+ case R_ARM_ALU_PC_G1_NC:
+ case R_ARM_ALU_PC_G0:
+ case R_ARM_ALU_PC_G1:
+ case R_ARM_ALU_PC_G2:
+ case R_ARM_ALU_SB_G0_NC:
+ case R_ARM_ALU_SB_G1_NC:
+ case R_ARM_ALU_SB_G0:
+ case R_ARM_ALU_SB_G1:
+ case R_ARM_ALU_SB_G2:
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+ bfd_vma pc = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ /* sb should be the origin of the *segment* containing the symbol.
+ It is not clear how to obtain this OS-dependent value, so we
+ make an arbitrary choice of zero. */
+ bfd_vma sb = 0;
+ bfd_vma residual;
+ bfd_vma g_n;
+ bfd_signed_vma signed_value;
+ int group = 0;
+
+ /* Determine which group of bits to select. */
+ switch (r_type)
+ {
+ case R_ARM_ALU_PC_G0_NC:
+ case R_ARM_ALU_PC_G0:
+ case R_ARM_ALU_SB_G0_NC:
+ case R_ARM_ALU_SB_G0:
+ group = 0;
+ break;
+
+ case R_ARM_ALU_PC_G1_NC:
+ case R_ARM_ALU_PC_G1:
+ case R_ARM_ALU_SB_G1_NC:
+ case R_ARM_ALU_SB_G1:
+ group = 1;
+ break;
+
+ case R_ARM_ALU_PC_G2:
+ case R_ARM_ALU_SB_G2:
+ group = 2;
+ break;
+
+ default:
+ abort();
+ }
+
+ /* If REL, extract the addend from the insn. If RELA, it will
+ have already been fetched for us. */
+ if (globals->use_rel)
+ {
+ int negative;
+ bfd_vma constant = insn & 0xff;
+ bfd_vma rotation = (insn & 0xf00) >> 8;
+
+ if (rotation == 0)
+ signed_addend = constant;
+ else
+ {
+ /* Compensate for the fact that in the instruction, the
+ rotation is stored in multiples of 2 bits. */
+ rotation *= 2;
+
+ /* Rotate "constant" right by "rotation" bits. */
+ signed_addend = (constant >> rotation) |
+ (constant << (8 * sizeof (bfd_vma) - rotation));
+ }
+
+ /* Determine if the instruction is an ADD or a SUB.
+ (For REL, this determines the sign of the addend.) */
+ negative = identify_add_or_sub (insn);
+ if (negative == 0)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): Only ADD or SUB instructions are allowed for ALU group relocations"),
+ input_bfd, input_section,
+ (long) rel->r_offset, howto->name);
+ return bfd_reloc_overflow;
+ }
+
+ signed_addend *= negative;
+ }
+
+ /* Compute the value (X) to go in the place. */
+ if (r_type == R_ARM_ALU_PC_G0_NC
+ || r_type == R_ARM_ALU_PC_G1_NC
+ || r_type == R_ARM_ALU_PC_G0
+ || r_type == R_ARM_ALU_PC_G1
+ || r_type == R_ARM_ALU_PC_G2)
+ /* PC relative. */
+ signed_value = value - pc + signed_addend;
+ else
+ /* Section base relative. */
+ signed_value = value - sb + signed_addend;
+
+ /* If the target symbol is a Thumb function, then set the
+ Thumb bit in the address. */
+ if (sym_flags == STT_ARM_TFUNC)
+ signed_value |= 1;
+
+ /* Calculate the value of the relevant G_n, in encoded
+ constant-with-rotation format. */
+ g_n = calculate_group_reloc_mask (abs (signed_value), group,
+ &residual);
+
+ /* Check for overflow if required. */
+ if ((r_type == R_ARM_ALU_PC_G0
+ || r_type == R_ARM_ALU_PC_G1
+ || r_type == R_ARM_ALU_PC_G2
+ || r_type == R_ARM_ALU_SB_G0
+ || r_type == R_ARM_ALU_SB_G1
+ || r_type == R_ARM_ALU_SB_G2) && residual != 0)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+ input_bfd, input_section,
+ (long) rel->r_offset, abs (signed_value), howto->name);
+ return bfd_reloc_overflow;
+ }
+
+ /* Mask out the value and the ADD/SUB part of the opcode; take care
+ not to destroy the S bit. */
+ insn &= 0xff1ff000;
+
+ /* Set the opcode according to whether the value to go in the
+ place is negative. */
+ if (signed_value < 0)
+ insn |= 1 << 22;
+ else
+ insn |= 1 << 23;
+
+ /* Encode the offset. */
+ insn |= g_n;
+
+ bfd_put_32 (input_bfd, insn, hit_data);
+ }
+ return bfd_reloc_ok;
+
+ case R_ARM_LDR_PC_G0:
+ case R_ARM_LDR_PC_G1:
+ case R_ARM_LDR_PC_G2:
+ case R_ARM_LDR_SB_G0:
+ case R_ARM_LDR_SB_G1:
+ case R_ARM_LDR_SB_G2:
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+ bfd_vma pc = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ bfd_vma sb = 0; /* See note above. */
+ bfd_vma residual;
+ bfd_signed_vma signed_value;
+ int group = 0;
+
+ /* Determine which groups of bits to calculate. */
+ switch (r_type)
+ {
+ case R_ARM_LDR_PC_G0:
+ case R_ARM_LDR_SB_G0:
+ group = 0;
+ break;
+
+ case R_ARM_LDR_PC_G1:
+ case R_ARM_LDR_SB_G1:
+ group = 1;
+ break;
+
+ case R_ARM_LDR_PC_G2:
+ case R_ARM_LDR_SB_G2:
+ group = 2;
+ break;
+
+ default:
+ abort();
+ }
+
+ /* If REL, extract the addend from the insn. If RELA, it will
+ have already been fetched for us. */
+ if (globals->use_rel)
+ {
+ int negative = (insn & (1 << 23)) ? 1 : -1;
+ signed_addend = negative * (insn & 0xfff);
+ }
+
+ /* Compute the value (X) to go in the place. */
+ if (r_type == R_ARM_LDR_PC_G0
+ || r_type == R_ARM_LDR_PC_G1
+ || r_type == R_ARM_LDR_PC_G2)
+ /* PC relative. */
+ signed_value = value - pc + signed_addend;
+ else
+ /* Section base relative. */
+ signed_value = value - sb + signed_addend;
+
+ /* Calculate the value of the relevant G_{n-1} to obtain
+ the residual at that stage. */
+ calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+
+ /* Check for overflow. */
+ if (residual >= 0x1000)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+ input_bfd, input_section,
+ (long) rel->r_offset, abs (signed_value), howto->name);
+ return bfd_reloc_overflow;
+ }
+
+ /* Mask out the value and U bit. */
+ insn &= 0xff7ff000;
+
+ /* Set the U bit if the value to go in the place is non-negative. */
+ if (signed_value >= 0)
+ insn |= 1 << 23;
+
+ /* Encode the offset. */
+ insn |= residual;
+
+ bfd_put_32 (input_bfd, insn, hit_data);
+ }
+ return bfd_reloc_ok;
+
+ case R_ARM_LDRS_PC_G0:
+ case R_ARM_LDRS_PC_G1:
+ case R_ARM_LDRS_PC_G2:
+ case R_ARM_LDRS_SB_G0:
+ case R_ARM_LDRS_SB_G1:
+ case R_ARM_LDRS_SB_G2:
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+ bfd_vma pc = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ bfd_vma sb = 0; /* See note above. */
+ bfd_vma residual;
+ bfd_signed_vma signed_value;
+ int group = 0;
+
+ /* Determine which groups of bits to calculate. */
+ switch (r_type)
+ {
+ case R_ARM_LDRS_PC_G0:
+ case R_ARM_LDRS_SB_G0:
+ group = 0;
+ break;
+
+ case R_ARM_LDRS_PC_G1:
+ case R_ARM_LDRS_SB_G1:
+ group = 1;
+ break;
+
+ case R_ARM_LDRS_PC_G2:
+ case R_ARM_LDRS_SB_G2:
+ group = 2;
+ break;
+
+ default:
+ abort();
+ }
+
+ /* If REL, extract the addend from the insn. If RELA, it will
+ have already been fetched for us. */
+ if (globals->use_rel)
+ {
+ int negative = (insn & (1 << 23)) ? 1 : -1;
+ signed_addend = negative * (((insn & 0xf00) >> 4) + (insn & 0xf));
+ }
+
+ /* Compute the value (X) to go in the place. */
+ if (r_type == R_ARM_LDRS_PC_G0
+ || r_type == R_ARM_LDRS_PC_G1
+ || r_type == R_ARM_LDRS_PC_G2)
+ /* PC relative. */
+ signed_value = value - pc + signed_addend;
+ else
+ /* Section base relative. */
+ signed_value = value - sb + signed_addend;
+
+ /* Calculate the value of the relevant G_{n-1} to obtain
+ the residual at that stage. */
+ calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+
+ /* Check for overflow. */
+ if (residual >= 0x100)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+ input_bfd, input_section,
+ (long) rel->r_offset, abs (signed_value), howto->name);
+ return bfd_reloc_overflow;
+ }
+
+ /* Mask out the value and U bit. */
+ insn &= 0xff7ff0f0;
+
+ /* Set the U bit if the value to go in the place is non-negative. */
+ if (signed_value >= 0)
+ insn |= 1 << 23;
+
+ /* Encode the offset. */
+ insn |= ((residual & 0xf0) << 4) | (residual & 0xf);
+
+ bfd_put_32 (input_bfd, insn, hit_data);
+ }
+ return bfd_reloc_ok;
+
+ case R_ARM_LDC_PC_G0:
+ case R_ARM_LDC_PC_G1:
+ case R_ARM_LDC_PC_G2:
+ case R_ARM_LDC_SB_G0:
+ case R_ARM_LDC_SB_G1:
+ case R_ARM_LDC_SB_G2:
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+ bfd_vma pc = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ bfd_vma sb = 0; /* See note above. */
+ bfd_vma residual;
+ bfd_signed_vma signed_value;
+ int group = 0;
+
+ /* Determine which groups of bits to calculate. */
+ switch (r_type)
+ {
+ case R_ARM_LDC_PC_G0:
+ case R_ARM_LDC_SB_G0:
+ group = 0;
+ break;
+
+ case R_ARM_LDC_PC_G1:
+ case R_ARM_LDC_SB_G1:
+ group = 1;
+ break;
+
+ case R_ARM_LDC_PC_G2:
+ case R_ARM_LDC_SB_G2:
+ group = 2;
+ break;
+
+ default:
+ abort();
+ }
+
+ /* If REL, extract the addend from the insn. If RELA, it will
+ have already been fetched for us. */
+ if (globals->use_rel)
+ {
+ int negative = (insn & (1 << 23)) ? 1 : -1;
+ signed_addend = negative * ((insn & 0xff) << 2);
+ }
+
+ /* Compute the value (X) to go in the place. */
+ if (r_type == R_ARM_LDC_PC_G0
+ || r_type == R_ARM_LDC_PC_G1
+ || r_type == R_ARM_LDC_PC_G2)
+ /* PC relative. */
+ signed_value = value - pc + signed_addend;
+ else
+ /* Section base relative. */
+ signed_value = value - sb + signed_addend;
+
+ /* Calculate the value of the relevant G_{n-1} to obtain
+ the residual at that stage. */
+ calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+
+ /* Check for overflow. (The absolute value to go in the place must be
+ divisible by four and, after having been divided by four, must
+ fit in eight bits.) */
+ if ((residual & 0x3) != 0 || residual >= 0x400)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+ input_bfd, input_section,
+ (long) rel->r_offset, abs (signed_value), howto->name);
+ return bfd_reloc_overflow;
+ }
+
+ /* Mask out the value and U bit. */
+ insn &= 0xff7fff00;
+
+ /* Set the U bit if the value to go in the place is non-negative. */
+ if (signed_value >= 0)
+ insn |= 1 << 23;
+
+ /* Encode the offset. */
+ insn |= residual >> 2;
+
+ bfd_put_32 (input_bfd, insn, hit_data);
+ }
+ return bfd_reloc_ok;
+
default:
return bfd_reloc_notsupported;
}