This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
This patch provides gas and ld support for the ARM AAELF "group relocations" (numbers 4, and 57 through 83). Herewith are attached:
- the part of the patch that is just a diff; - a tarball containing the new gas test cases; - a tarball containing the new ld test cases.
Regtested on x86_64 with arm-none-linux-gnueabi target. I've subjected this to fairly extensive testing via other means as well.
This patch does require Julian Brown's "[PATCH, ARM] Re-use VFP encoding functions for VLDR/VSTR" that he posted here on 5th June.
* 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-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.
* 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/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-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.
Attachment:
group-relocs-57-83-gastests.tar.gz
Description: GNU Zip compressed data
Index: bfd/elf32-arm.c =================================================================== RCS file: /cvs/src/src/bfd/elf32-arm.c,v retrieving revision 1.78 diff -U3 -p -r1.78 elf32-arm.c --- bfd/elf32-arm.c 30 May 2006 16:45:31 -0000 1.78 +++ bfd/elf32-arm.c 7 Jun 2006 14:42:07 -0000 @@ -130,19 +130,19 @@ static reloc_howto_type elf32_arm_howto_ 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_ 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_ 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 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 {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 * 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_how } 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; } Index: bfd/reloc.c =================================================================== RCS file: /cvs/src/src/bfd/reloc.c,v retrieving revision 1.154 diff -U3 -p -r1.154 reloc.c --- bfd/reloc.c 24 May 2006 07:36:09 -0000 1.154 +++ bfd/reloc.c 7 Jun 2006 14:42:08 -0000 @@ -2757,6 +2757,65 @@ ENUMDOC ARM thread-local storage relocations. ENUM + BFD_RELOC_ARM_ALU_PC_G0_NC +ENUMX + BFD_RELOC_ARM_ALU_PC_G0 +ENUMX + BFD_RELOC_ARM_ALU_PC_G1_NC +ENUMX + BFD_RELOC_ARM_ALU_PC_G1 +ENUMX + BFD_RELOC_ARM_ALU_PC_G2 +ENUMX + BFD_RELOC_ARM_LDR_PC_G0 +ENUMX + BFD_RELOC_ARM_LDR_PC_G1 +ENUMX + BFD_RELOC_ARM_LDR_PC_G2 +ENUMX + BFD_RELOC_ARM_LDRS_PC_G0 +ENUMX + BFD_RELOC_ARM_LDRS_PC_G1 +ENUMX + BFD_RELOC_ARM_LDRS_PC_G2 +ENUMX + BFD_RELOC_ARM_LDC_PC_G0 +ENUMX + BFD_RELOC_ARM_LDC_PC_G1 +ENUMX + BFD_RELOC_ARM_LDC_PC_G2 +ENUMX + BFD_RELOC_ARM_ALU_SB_G0_NC +ENUMX + BFD_RELOC_ARM_ALU_SB_G0 +ENUMX + BFD_RELOC_ARM_ALU_SB_G1_NC +ENUMX + BFD_RELOC_ARM_ALU_SB_G1 +ENUMX + BFD_RELOC_ARM_ALU_SB_G2 +ENUMX + BFD_RELOC_ARM_LDR_SB_G0 +ENUMX + BFD_RELOC_ARM_LDR_SB_G1 +ENUMX + BFD_RELOC_ARM_LDR_SB_G2 +ENUMX + BFD_RELOC_ARM_LDRS_SB_G0 +ENUMX + BFD_RELOC_ARM_LDRS_SB_G1 +ENUMX + BFD_RELOC_ARM_LDRS_SB_G2 +ENUMX + BFD_RELOC_ARM_LDC_SB_G0 +ENUMX + BFD_RELOC_ARM_LDC_SB_G1 +ENUMX + BFD_RELOC_ARM_LDC_SB_G2 +ENUMDOC + ARM group relocations. + +ENUM BFD_RELOC_ARM_IMMEDIATE ENUMX BFD_RELOC_ARM_ADRL_IMMEDIATE Index: gas/config/tc-arm.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-arm.c,v retrieving revision 1.274 diff -U3 -p -r1.274 tc-arm.c --- gas/config/tc-arm.c 7 Jun 2006 14:32:28 -0000 1.274 +++ gas/config/tc-arm.c 7 Jun 2006 14:42:15 -0000 @@ -79,6 +79,15 @@ static struct unsigned sp_restored:1; } unwind; +/* Results from operand parsing worker functions. */ + +typedef enum +{ + PARSE_OPERAND_SUCCESS, + PARSE_OPERAND_FAIL, + PARSE_OPERAND_FAIL_NO_BACKTRACK +} parse_operand_result; + /* Bit N indicates that an R_ARM_NONE relocation has been output for __aeabi_unwind_cpp_prN already if set. This enables dependencies to be emitted only once per section, to save unnecessary bloat. */ @@ -4261,6 +4270,168 @@ parse_shifter_operand (char **str, int i return SUCCESS; } +/* Group relocation information. Each entry in the table contains the + textual name of the relocation as may appear in assembler source + and must end with a colon. + Along with this textual name are the relocation codes to be used if + the corresponding instruction is an ALU instruction (ADD or SUB only), + an LDR, an LDRS, or an LDC. */ + +struct group_reloc_table_entry +{ + const char *name; + int alu_code; + int ldr_code; + int ldrs_code; + int ldc_code; +}; + +typedef enum +{ + /* Varieties of non-ALU group relocation. */ + + GROUP_LDR, + GROUP_LDRS, + GROUP_LDC +} group_reloc_type; + +static struct group_reloc_table_entry group_reloc_table[] = + { /* Program counter relative: */ + { "pc_g0_nc", + BFD_RELOC_ARM_ALU_PC_G0_NC, /* ALU */ + 0, /* LDR */ + 0, /* LDRS */ + 0 }, /* LDC */ + { "pc_g0", + BFD_RELOC_ARM_ALU_PC_G0, /* ALU */ + BFD_RELOC_ARM_LDR_PC_G0, /* LDR */ + BFD_RELOC_ARM_LDRS_PC_G0, /* LDRS */ + BFD_RELOC_ARM_LDC_PC_G0 }, /* LDC */ + { "pc_g1_nc", + BFD_RELOC_ARM_ALU_PC_G1_NC, /* ALU */ + 0, /* LDR */ + 0, /* LDRS */ + 0 }, /* LDC */ + { "pc_g1", + BFD_RELOC_ARM_ALU_PC_G1, /* ALU */ + BFD_RELOC_ARM_LDR_PC_G1, /* LDR */ + BFD_RELOC_ARM_LDRS_PC_G1, /* LDRS */ + BFD_RELOC_ARM_LDC_PC_G1 }, /* LDC */ + { "pc_g2", + BFD_RELOC_ARM_ALU_PC_G2, /* ALU */ + BFD_RELOC_ARM_LDR_PC_G2, /* LDR */ + BFD_RELOC_ARM_LDRS_PC_G2, /* LDRS */ + BFD_RELOC_ARM_LDC_PC_G2 }, /* LDC */ + /* Section base relative */ + { "sb_g0_nc", + BFD_RELOC_ARM_ALU_SB_G0_NC, /* ALU */ + 0, /* LDR */ + 0, /* LDRS */ + 0 }, /* LDC */ + { "sb_g0", + BFD_RELOC_ARM_ALU_SB_G0, /* ALU */ + BFD_RELOC_ARM_LDR_SB_G0, /* LDR */ + BFD_RELOC_ARM_LDRS_SB_G0, /* LDRS */ + BFD_RELOC_ARM_LDC_SB_G0 }, /* LDC */ + { "sb_g1_nc", + BFD_RELOC_ARM_ALU_SB_G1_NC, /* ALU */ + 0, /* LDR */ + 0, /* LDRS */ + 0 }, /* LDC */ + { "sb_g1", + BFD_RELOC_ARM_ALU_SB_G1, /* ALU */ + BFD_RELOC_ARM_LDR_SB_G1, /* LDR */ + BFD_RELOC_ARM_LDRS_SB_G1, /* LDRS */ + BFD_RELOC_ARM_LDC_SB_G1 }, /* LDC */ + { "sb_g2", + BFD_RELOC_ARM_ALU_SB_G2, /* ALU */ + BFD_RELOC_ARM_LDR_SB_G2, /* LDR */ + BFD_RELOC_ARM_LDRS_SB_G2, /* LDRS */ + BFD_RELOC_ARM_LDC_SB_G2 } }; /* LDC */ + +/* Given the address of a pointer pointing to the textual name of a group + relocation as may appear in assembler source, attempt to find its details + in group_reloc_table. The pointer will be updated to the character after + the trailing colon. On failure, FAIL will be returned; SUCCESS + otherwise. On success, *entry will be updated to point at the relevant + group_reloc_table entry. */ + +static int +find_group_reloc_table_entry (char **str, struct group_reloc_table_entry **out) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE (group_reloc_table); i++) + { + int length = strlen (group_reloc_table[i].name); + + if (strncasecmp (group_reloc_table[i].name, *str, length) == 0 && + (*str)[length] == ':') + { + *out = &group_reloc_table[i]; + *str += (length + 1); + return SUCCESS; + } + } + + return FAIL; +} + +/* Parse a <shifter_operand> for an ARM data processing instruction + (as for parse_shifter_operand) where group relocations are allowed: + + #<immediate> + #<immediate>, <rotate> + #:<group_reloc>:<expression> + <Rm> + <Rm>, <shift> + + where <group_reloc> is one of the strings defined in group_reloc_table. + The hashes are optional. + + Everything else is as for parse_shifter_operand. */ + +static parse_operand_result +parse_shifter_operand_group_reloc (char **str, int i) +{ + /* Determine if we have the sequence of characters #: or just : + coming next. If we do, then we check for a group relocation. + If we don't, punt the whole lot to parse_shifter_operand. */ + + if (((*str)[0] == '#' && (*str)[1] == ':') + || (*str)[0] == ':') + { + struct group_reloc_table_entry *entry; + + if ((*str)[0] == '#') + (*str) += 2; + else + (*str)++; + + /* Try to parse a group relocation. Anything else is an error. */ + if (find_group_reloc_table_entry (str, &entry) == FAIL) + { + inst.error = _("unknown group relocation"); + return PARSE_OPERAND_FAIL_NO_BACKTRACK; + } + + /* We now have the group relocation table entry corresponding to + the name in the assembler source. Next, we parse the expression. */ + if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX)) + return PARSE_OPERAND_FAIL_NO_BACKTRACK; + + /* Record the relocation type (always the ALU variant here). */ + inst.reloc.type = entry->alu_code; + assert (inst.reloc.type != 0); + + return PARSE_OPERAND_SUCCESS; + } + else + return parse_shifter_operand (str, i) == SUCCESS + ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL; + + /* Never reached. */ +} + /* Parse all forms of an ARM address expression. Information is written to inst.operands[i] and/or inst.reloc. @@ -4293,8 +4464,9 @@ parse_shifter_operand (char **str, int i It is the caller's responsibility to check for addressing modes not supported by the instruction, and to set inst.reloc.type. */ -static int -parse_address (char **str, int i) +static parse_operand_result +parse_address_main (char **str, int i, int group_relocations, + group_reloc_type group_type) { char *p = *str; int reg; @@ -4312,16 +4484,16 @@ parse_address (char **str, int i) /* else a load-constant pseudo op, no special treatment needed here */ if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX)) - return FAIL; + return PARSE_OPERAND_FAIL; *str = p; - return SUCCESS; + return PARSE_OPERAND_SUCCESS; } if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL) { inst.error = _(reg_expected_msgs[REG_TYPE_RN]); - return FAIL; + return PARSE_OPERAND_FAIL; } inst.operands[i].reg = reg; inst.operands[i].isreg = 1; @@ -4340,7 +4512,7 @@ parse_address (char **str, int i) if (skip_past_comma (&p) == SUCCESS) if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL) - return FAIL; + return PARSE_OPERAND_FAIL; } else if (skip_past_char (&p, ':') == SUCCESS) { @@ -4352,7 +4524,7 @@ parse_address (char **str, int i) if (exp.X_op != O_constant) { inst.error = _("alignment must be constant"); - return FAIL; + return PARSE_OPERAND_FAIL; } inst.operands[i].imm = exp.X_add_number << 8; inst.operands[i].immisalign = 1; @@ -4366,15 +4538,68 @@ parse_address (char **str, int i) inst.operands[i].negative = 0; p--; } - if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) - return FAIL; + + if (group_relocations && + ((*p == '#' && *(p + 1) == ':') || *p == ':')) + + { + struct group_reloc_table_entry *entry; + + /* Skip over the #: or : sequence. */ + if (*p == '#') + p += 2; + else + p++; + + /* Try to parse a group relocation. Anything else is an + error. */ + if (find_group_reloc_table_entry (&p, &entry) == FAIL) + { + inst.error = _("unknown group relocation"); + return PARSE_OPERAND_FAIL_NO_BACKTRACK; + } + + /* We now have the group relocation table entry corresponding to + the name in the assembler source. Next, we parse the + expression. */ + if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX)) + return PARSE_OPERAND_FAIL_NO_BACKTRACK; + + /* Record the relocation type. */ + switch (group_type) + { + case GROUP_LDR: + inst.reloc.type = entry->ldr_code; + break; + + case GROUP_LDRS: + inst.reloc.type = entry->ldrs_code; + break; + + case GROUP_LDC: + inst.reloc.type = entry->ldc_code; + break; + + default: + assert (0); + } + + if (inst.reloc.type == 0) + { + inst.error = _("this group relocation is not allowed on this instruction"); + return PARSE_OPERAND_FAIL_NO_BACKTRACK; + } + } + else + if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + return PARSE_OPERAND_FAIL; } } if (skip_past_char (&p, ']') == FAIL) { inst.error = _("']' expected"); - return FAIL; + return PARSE_OPERAND_FAIL; } if (skip_past_char (&p, '!') == SUCCESS) @@ -4387,20 +4612,20 @@ parse_address (char **str, int i) /* [Rn], {expr} - unindexed, with option */ if (parse_immediate (&p, &inst.operands[i].imm, 0, 255, TRUE) == FAIL) - return FAIL; + return PARSE_OPERAND_FAIL; if (skip_past_char (&p, '}') == FAIL) { inst.error = _("'}' expected at end of 'option' field"); - return FAIL; + return PARSE_OPERAND_FAIL; } if (inst.operands[i].preind) { inst.error = _("cannot combine index with option"); - return FAIL; + return PARSE_OPERAND_FAIL; } *str = p; - return SUCCESS; + return PARSE_OPERAND_SUCCESS; } else { @@ -4410,7 +4635,7 @@ parse_address (char **str, int i) if (inst.operands[i].preind) { inst.error = _("cannot combine pre- and post-indexing"); - return FAIL; + return PARSE_OPERAND_FAIL; } if (*p == '+') p++; @@ -4428,7 +4653,7 @@ parse_address (char **str, int i) if (skip_past_comma (&p) == SUCCESS) if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL) - return FAIL; + return PARSE_OPERAND_FAIL; } else { @@ -4438,7 +4663,7 @@ parse_address (char **str, int i) p--; } if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) - return FAIL; + return PARSE_OPERAND_FAIL; } } } @@ -4452,7 +4677,20 @@ parse_address (char **str, int i) inst.reloc.exp.X_add_number = 0; } *str = p; - return SUCCESS; + return PARSE_OPERAND_SUCCESS; +} + +static int +parse_address (char **str, int i) +{ + return parse_address_main (str, i, 0, 0) == PARSE_OPERAND_SUCCESS + ? SUCCESS : FAIL; +} + +static parse_operand_result +parse_address_group_reloc (char **str, int i, group_reloc_type type) +{ + return parse_address_main (str, i, 1, type); } /* Parse an operand for a MOVW or MOVT instruction. */ @@ -5051,7 +5289,11 @@ enum operand_parse_code OP_I31b, /* 0 .. 31 */ OP_SH, /* shifter operand */ + OP_SHG, /* shifter operand with possible group relocation */ OP_ADDR, /* Memory address expression (any mode) */ + OP_ADDRGLDR, /* Mem addr expr (any mode) with possible LDR group reloc */ + OP_ADDRGLDRS, /* Mem addr expr (any mode) with possible LDRS group reloc */ + OP_ADDRGLDC, /* Mem addr expr (any mode) with possible LDC group reloc */ OP_EXP, /* arbitrary expression */ OP_EXPi, /* same, with optional immediate prefix */ OP_EXPr, /* same, with optional relocation suffix */ @@ -5106,6 +5348,7 @@ parse_operands (char *str, const unsigne const char *backtrack_error = 0; int i, val, backtrack_index = 0; enum arm_reg_type rtype; + parse_operand_result result; #define po_char_or_fail(chr) do { \ if (skip_past_char (&str, chr) == FAIL) \ @@ -5163,6 +5406,14 @@ parse_operands (char *str, const unsigne goto failure; \ } while (0) +#define po_misc_or_fail_no_backtrack(expr) do { \ + result = expr; \ + if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK)\ + backtrack_pos = 0; \ + if (result != PARSE_OPERAND_SUCCESS) \ + goto failure; \ +} while (0) + skip_whitespace (str); for (i = 0; upat[i] != OP_stop; i++) @@ -5545,10 +5796,30 @@ parse_operands (char *str, const unsigne po_misc_or_fail (parse_address (&str, i)); break; + case OP_ADDRGLDR: + po_misc_or_fail_no_backtrack ( + parse_address_group_reloc (&str, i, GROUP_LDR)); + break; + + case OP_ADDRGLDRS: + po_misc_or_fail_no_backtrack ( + parse_address_group_reloc (&str, i, GROUP_LDRS)); + break; + + case OP_ADDRGLDC: + po_misc_or_fail_no_backtrack ( + parse_address_group_reloc (&str, i, GROUP_LDC)); + break; + case OP_SH: po_misc_or_fail (parse_shifter_operand (&str, i)); break; + case OP_SHG: + po_misc_or_fail_no_backtrack ( + parse_shifter_operand_group_reloc (&str, i)); + break; + case OP_oSHll: po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE)); break; @@ -5902,7 +6173,8 @@ encode_arm_addr_mode_3 (int i, bfd_boole into a coprocessor load/store instruction. If wb_ok is false, reject use of writeback; if unind_ok is false, reject use of unindexed addressing. If reloc_override is not 0, use it instead - of BFD_ARM_CP_OFF_IMM. */ + of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one + (in which case it is preserved). */ static int encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override) @@ -5944,10 +6216,16 @@ encode_arm_cp_address (int i, int wb_ok, if (reloc_override) inst.reloc.type = reloc_override; - else if (thumb_mode) - inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM; - else - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; + else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC + || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2) + && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0) + { + if (thumb_mode) + inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM; + else + inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; + } + return SUCCESS; } @@ -14085,8 +14363,8 @@ static const struct asm_opcode insns[] = tC3(eors, 0300000, eors, 3, (RR, oRR, SH), arit, t_arit3c), tCE(sub, 0400000, sub, 3, (RR, oRR, SH), arit, t_add_sub), tC3(subs, 0500000, subs, 3, (RR, oRR, SH), arit, t_add_sub), - tCE(add, 0800000, add, 3, (RR, oRR, SH), arit, t_add_sub), - tC3(adds, 0900000, adds, 3, (RR, oRR, SH), arit, t_add_sub), + tCE(add, 0800000, add, 3, (RR, oRR, SHG), arit, t_add_sub), + tC3(adds, 0900000, adds, 3, (RR, oRR, SHG), arit, t_add_sub), tCE(adc, 0a00000, adc, 3, (RR, oRR, SH), arit, t_arit3c), tC3(adcs, 0b00000, adcs, 3, (RR, oRR, SH), arit, t_arit3c), tCE(sbc, 0c00000, sbc, 3, (RR, oRR, SH), arit, t_arit3), @@ -14114,10 +14392,10 @@ static const struct asm_opcode insns[] = tCE(mvn, 1e00000, mvn, 2, (RR, SH), mov, t_mvn_tst), tC3(mvns, 1f00000, mvns, 2, (RR, SH), mov, t_mvn_tst), - tCE(ldr, 4100000, ldr, 2, (RR, ADDR), ldst, t_ldst), - tC3(ldrb, 4500000, ldrb, 2, (RR, ADDR), ldst, t_ldst), - tCE(str, 4000000, str, 2, (RR, ADDR), ldst, t_ldst), - tC3(strb, 4400000, strb, 2, (RR, ADDR), ldst, t_ldst), + tCE(ldr, 4100000, ldr, 2, (RR, ADDRGLDR),ldst, t_ldst), + tC3(ldrb, 4500000, ldrb, 2, (RR, ADDRGLDR),ldst, t_ldst), + tCE(str, 4000000, str, 2, (RR, ADDRGLDR),ldst, t_ldst), + tC3(strb, 4400000, strb, 2, (RR, ADDRGLDR),ldst, t_ldst), tCE(stm, 8800000, stmia, 2, (RRw, REGLST), ldmstm, t_ldmstm), tC3(stmia, 8800000, stmia, 2, (RRw, REGLST), ldmstm, t_ldmstm), @@ -14201,10 +14479,10 @@ static const struct asm_opcode insns[] = /* Generic coprocessor instructions. */ TCE(cdp, e000000, ee000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp, cdp), - TCE(ldc, c100000, ec100000, 3, (RCP, RCN, ADDR), lstc, lstc), - TC3(ldcl, c500000, ec500000, 3, (RCP, RCN, ADDR), lstc, lstc), - TCE(stc, c000000, ec000000, 3, (RCP, RCN, ADDR), lstc, lstc), - TC3(stcl, c400000, ec400000, 3, (RCP, RCN, ADDR), lstc, lstc), + TCE(ldc, c100000, ec100000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), + TC3(ldcl, c500000, ec500000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), + TCE(stc, c000000, ec000000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), + TC3(stcl, c400000, ec400000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), TCE(mcr, e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), TCE(mrc, e100010, ee100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), @@ -14233,12 +14511,12 @@ static const struct asm_opcode insns[] = #define ARM_VARIANT &arm_ext_v4 /* ARM Architecture 4. */ #undef THUMB_VARIANT #define THUMB_VARIANT &arm_ext_v4t - tC3(ldrh, 01000b0, ldrh, 2, (RR, ADDR), ldstv4, t_ldst), - tC3(strh, 00000b0, strh, 2, (RR, ADDR), ldstv4, t_ldst), - tC3(ldrsh, 01000f0, ldrsh, 2, (RR, ADDR), ldstv4, t_ldst), - tC3(ldrsb, 01000d0, ldrsb, 2, (RR, ADDR), ldstv4, t_ldst), - tCM(ld,sh, 01000f0, ldrsh, 2, (RR, ADDR), ldstv4, t_ldst), - tCM(ld,sb, 01000d0, ldrsb, 2, (RR, ADDR), ldstv4, t_ldst), + tC3(ldrh, 01000b0, ldrh, 2, (RR, ADDRGLDRS), ldstv4, t_ldst), + tC3(strh, 00000b0, strh, 2, (RR, ADDRGLDRS), ldstv4, t_ldst), + tC3(ldrsh, 01000f0, ldrsh, 2, (RR, ADDRGLDRS), ldstv4, t_ldst), + tC3(ldrsb, 01000d0, ldrsb, 2, (RR, ADDRGLDRS), ldstv4, t_ldst), + tCM(ld,sh, 01000f0, ldrsh, 2, (RR, ADDRGLDRS), ldstv4, t_ldst), + tCM(ld,sb, 01000d0, ldrsb, 2, (RR, ADDRGLDRS), ldstv4, t_ldst), #undef ARM_VARIANT #define ARM_VARIANT &arm_ext_v4t_5 @@ -14259,10 +14537,10 @@ static const struct asm_opcode insns[] = #undef THUMB_VARIANT #define THUMB_VARIANT &arm_ext_v6t2 TCE(clz, 16f0f10, fab0f080, 2, (RRnpc, RRnpc), rd_rm, t_clz), - TUF(ldc2, c100000, fc100000, 3, (RCP, RCN, ADDR), lstc, lstc), - TUF(ldc2l, c500000, fc500000, 3, (RCP, RCN, ADDR), lstc, lstc), - TUF(stc2, c000000, fc000000, 3, (RCP, RCN, ADDR), lstc, lstc), - TUF(stc2l, c400000, fc400000, 3, (RCP, RCN, ADDR), lstc, lstc), + TUF(ldc2, c100000, fc100000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), + TUF(ldc2l, c500000, fc500000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), + TUF(stc2, c000000, fc000000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), + TUF(stc2l, c400000, fc400000, 3, (RCP, RCN, ADDRGLDC), lstc, lstc), TUF(cdp2, e000000, fe000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp, cdp), TUF(mcr2, e000010, fe000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), TUF(mrc2, e100010, fe100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), @@ -14298,8 +14576,8 @@ static const struct asm_opcode insns[] = #undef ARM_VARIANT #define ARM_VARIANT &arm_ext_v5e /* ARM Architecture 5TE. */ TUF(pld, 450f000, f810f000, 1, (ADDR), pld, t_pld), - TC3(ldrd, 00000d0, e9500000, 3, (RRnpc, oRRnpc, ADDR), ldrd, t_ldstd), - TC3(strd, 00000f0, e9400000, 3, (RRnpc, oRRnpc, ADDR), ldrd, t_ldstd), + TC3(ldrd, 00000d0, e9500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd), + TC3(strd, 00000f0, e9400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd), TCE(mcrr, c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), TCE(mrrc, c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), @@ -14515,15 +14793,15 @@ static const struct asm_opcode insns[] = cCE(wfc, e400110, 1, (RR), rd), cCE(rfc, e500110, 1, (RR), rd), - cCL(ldfs, c100100, 2, (RF, ADDR), rd_cpaddr), - cCL(ldfd, c108100, 2, (RF, ADDR), rd_cpaddr), - cCL(ldfe, c500100, 2, (RF, ADDR), rd_cpaddr), - cCL(ldfp, c508100, 2, (RF, ADDR), rd_cpaddr), - - cCL(stfs, c000100, 2, (RF, ADDR), rd_cpaddr), - cCL(stfd, c008100, 2, (RF, ADDR), rd_cpaddr), - cCL(stfe, c400100, 2, (RF, ADDR), rd_cpaddr), - cCL(stfp, c408100, 2, (RF, ADDR), rd_cpaddr), + cCL(ldfs, c100100, 2, (RF, ADDRGLDC), rd_cpaddr), + cCL(ldfd, c108100, 2, (RF, ADDRGLDC), rd_cpaddr), + cCL(ldfe, c500100, 2, (RF, ADDRGLDC), rd_cpaddr), + cCL(ldfp, c508100, 2, (RF, ADDRGLDC), rd_cpaddr), + + cCL(stfs, c000100, 2, (RF, ADDRGLDC), rd_cpaddr), + cCL(stfd, c008100, 2, (RF, ADDRGLDC), rd_cpaddr), + cCL(stfe, c400100, 2, (RF, ADDRGLDC), rd_cpaddr), + cCL(stfp, c408100, 2, (RF, ADDRGLDC), rd_cpaddr), cCL(mvfs, e008100, 2, (RF, RF_IF), rd_rm), cCL(mvfsp, e008120, 2, (RF, RF_IF), rd_rm), @@ -14966,8 +15244,8 @@ static const struct asm_opcode insns[] = cCE(fmxr, ee00a10, 2, (RVC, RR), rn_rd), /* Memory operations. */ - cCE(flds, d100a00, 2, (RVS, ADDR), vfp_sp_ldst), - cCE(fsts, d000a00, 2, (RVS, ADDR), vfp_sp_ldst), + cCE(flds, d100a00, 2, (RVS, ADDRGLDC), vfp_sp_ldst), + cCE(fsts, d000a00, 2, (RVS, ADDRGLDC), vfp_sp_ldst), cCE(fldmias, c900a00, 2, (RRw, VRSLST), vfp_sp_ldstmia), cCE(fldmfds, c900a00, 2, (RRw, VRSLST), vfp_sp_ldstmia), cCE(fldmdbs, d300a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb), @@ -15025,8 +15303,8 @@ static const struct asm_opcode insns[] = cCE(ftouizd, ebc0bc0, 2, (RVS, RVD), vfp_sp_dp_cvt), /* Memory operations. */ - cCE(fldd, d100b00, 2, (RVD, ADDR), vfp_dp_ldst), - cCE(fstd, d000b00, 2, (RVD, ADDR), vfp_dp_ldst), + cCE(fldd, d100b00, 2, (RVD, ADDRGLDC), vfp_dp_ldst), + cCE(fstd, d000b00, 2, (RVD, ADDRGLDC), vfp_dp_ldst), cCE(fldmiad, c900b00, 2, (RRw, VRDLST), vfp_dp_ldstmia), cCE(fldmfdd, c900b00, 2, (RRw, VRDLST), vfp_dp_ldstmia), cCE(fldmdbd, d300b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb), @@ -15100,8 +15378,8 @@ static const struct asm_opcode insns[] = NCE(vstm, c800b00, 2, (RRw, VRSDLST), neon_ldm_stm), NCE(vstmia, c800b00, 2, (RRw, VRSDLST), neon_ldm_stm), NCE(vstmdb, d000b00, 2, (RRw, VRSDLST), neon_ldm_stm), - NCE(vldr, d100b00, 2, (RVSD, ADDR), neon_ldr_str), - NCE(vstr, d000b00, 2, (RVSD, ADDR), neon_ldr_str), + NCE(vldr, d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str), + NCE(vstr, d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str), nCEF(vcvt, vcvt, 3, (RNSDQ, RNSDQ, oI32b), neon_cvt), @@ -15557,14 +15835,14 @@ static const struct asm_opcode insns[] = #undef ARM_VARIANT #define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions. */ - cCE(cfldrs, c100400, 2, (RMF, ADDR), rd_cpaddr), - cCE(cfldrd, c500400, 2, (RMD, ADDR), rd_cpaddr), - cCE(cfldr32, c100500, 2, (RMFX, ADDR), rd_cpaddr), - cCE(cfldr64, c500500, 2, (RMDX, ADDR), rd_cpaddr), - cCE(cfstrs, c000400, 2, (RMF, ADDR), rd_cpaddr), - cCE(cfstrd, c400400, 2, (RMD, ADDR), rd_cpaddr), - cCE(cfstr32, c000500, 2, (RMFX, ADDR), rd_cpaddr), - cCE(cfstr64, c400500, 2, (RMDX, ADDR), rd_cpaddr), + cCE(cfldrs, c100400, 2, (RMF, ADDRGLDC), rd_cpaddr), + cCE(cfldrd, c500400, 2, (RMD, ADDRGLDC), rd_cpaddr), + cCE(cfldr32, c100500, 2, (RMFX, ADDRGLDC), rd_cpaddr), + cCE(cfldr64, c500500, 2, (RMDX, ADDRGLDC), rd_cpaddr), + cCE(cfstrs, c000400, 2, (RMF, ADDRGLDC), rd_cpaddr), + cCE(cfstrd, c400400, 2, (RMD, ADDRGLDC), rd_cpaddr), + cCE(cfstr32, c000500, 2, (RMFX, ADDRGLDC), rd_cpaddr), + cCE(cfstr64, c400500, 2, (RMDX, ADDRGLDC), rd_cpaddr), cCE(cfmvsr, e000450, 2, (RMF, RR), rn_rd), cCE(cfmvrs, e100450, 2, (RR, RMF), rd_rn), cCE(cfmvdlr, e000410, 2, (RMD, RR), rn_rd), @@ -16963,6 +17241,7 @@ md_apply_fix (fixS * fixP, assert (fixP->fx_r_type <= BFD_RELOC_UNUSED); /* Note whether this will delete the relocation. */ + if (fixP->fx_addsy == 0 && !fixP->fx_pcrel) fixP->fx_done = 1; @@ -17838,6 +18117,175 @@ md_apply_fix (fixS * fixP, } return; + case BFD_RELOC_ARM_ALU_PC_G0_NC: + case BFD_RELOC_ARM_ALU_PC_G0: + case BFD_RELOC_ARM_ALU_PC_G1_NC: + case BFD_RELOC_ARM_ALU_PC_G1: + case BFD_RELOC_ARM_ALU_PC_G2: + case BFD_RELOC_ARM_ALU_SB_G0_NC: + case BFD_RELOC_ARM_ALU_SB_G0: + case BFD_RELOC_ARM_ALU_SB_G1_NC: + case BFD_RELOC_ARM_ALU_SB_G1: + case BFD_RELOC_ARM_ALU_SB_G2: + assert (!fixP->fx_done); + if (!seg->use_rela_p) + { + bfd_vma insn; + bfd_vma encoded_addend; + bfd_vma addend_abs = abs (value); + + /* Check that the absolute value of the addend can be + expressed as an 8-bit constant plus a rotation. */ + encoded_addend = encode_arm_immediate (addend_abs); + if (encoded_addend == (unsigned int) FAIL) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("the offset 0x%08lX is not representable"), + addend_abs); + + /* Extract the instruction. */ + insn = md_chars_to_number (buf, INSN_SIZE); + + /* If the addend is positive, use an ADD instruction. + Otherwise use a SUB. Take care not to destroy the S bit. */ + insn &= 0xff1fffff; + if (value < 0) + insn |= 1 << 22; + else + insn |= 1 << 23; + + /* Place the encoded addend into the first 12 bits of the + instruction. */ + insn &= 0xfffff000; + insn |= encoded_addend; + + /* Update the instruction. */ + md_number_to_chars (buf, insn, INSN_SIZE); + } + break; + + case BFD_RELOC_ARM_LDR_PC_G0: + case BFD_RELOC_ARM_LDR_PC_G1: + case BFD_RELOC_ARM_LDR_PC_G2: + case BFD_RELOC_ARM_LDR_SB_G0: + case BFD_RELOC_ARM_LDR_SB_G1: + case BFD_RELOC_ARM_LDR_SB_G2: + assert (!fixP->fx_done); + if (!seg->use_rela_p) + { + bfd_vma insn; + bfd_vma addend_abs = abs (value); + + /* Check that the absolute value of the addend can be + encoded in 12 bits. */ + if (addend_abs >= 0x1000) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad offset 0x%08lX (only 12 bits available for the magnitude)"), + addend_abs); + + /* Extract the instruction. */ + insn = md_chars_to_number (buf, INSN_SIZE); + + /* If the addend is negative, clear bit 23 of the instruction. + Otherwise set it. */ + if (value < 0) + insn &= ~(1 << 23); + else + insn |= 1 << 23; + + /* Place the absolute value of the addend into the first 12 bits + of the instruction. */ + insn &= 0xfffff000; + insn |= addend_abs; + + /* Update the instruction. */ + md_number_to_chars (buf, insn, INSN_SIZE); + } + break; + + case BFD_RELOC_ARM_LDRS_PC_G0: + case BFD_RELOC_ARM_LDRS_PC_G1: + case BFD_RELOC_ARM_LDRS_PC_G2: + case BFD_RELOC_ARM_LDRS_SB_G0: + case BFD_RELOC_ARM_LDRS_SB_G1: + case BFD_RELOC_ARM_LDRS_SB_G2: + assert (!fixP->fx_done); + if (!seg->use_rela_p) + { + bfd_vma insn; + bfd_vma addend_abs = abs (value); + + /* Check that the absolute value of the addend can be + encoded in 8 bits. */ + if (addend_abs >= 0x100) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad offset 0x%08lX (only 8 bits available for the magnitude)"), + addend_abs); + + /* Extract the instruction. */ + insn = md_chars_to_number (buf, INSN_SIZE); + + /* If the addend is negative, clear bit 23 of the instruction. + Otherwise set it. */ + if (value < 0) + insn &= ~(1 << 23); + else + insn |= 1 << 23; + + /* Place the first four bits of the absolute value of the addend + into the first 4 bits of the instruction, and the remaining + four into bits 8 .. 11. */ + insn &= 0xfffff0f0; + insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4); + + /* Update the instruction. */ + md_number_to_chars (buf, insn, INSN_SIZE); + } + break; + + case BFD_RELOC_ARM_LDC_PC_G0: + case BFD_RELOC_ARM_LDC_PC_G1: + case BFD_RELOC_ARM_LDC_PC_G2: + case BFD_RELOC_ARM_LDC_SB_G0: + case BFD_RELOC_ARM_LDC_SB_G1: + case BFD_RELOC_ARM_LDC_SB_G2: + assert (!fixP->fx_done); + if (!seg->use_rela_p) + { + bfd_vma insn; + bfd_vma addend_abs = abs (value); + + /* Check that the absolute value of the addend is a multiple of + four and, when divided by four, fits in 8 bits. */ + if (addend_abs & 0x3) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad offset 0x%08lX (must be word-aligned)"), + addend_abs); + + if ((addend_abs >> 2) > 0xff) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad offset 0x%08lX (must be an 8-bit number of words)"), + addend_abs); + + /* Extract the instruction. */ + insn = md_chars_to_number (buf, INSN_SIZE); + + /* If the addend is negative, clear bit 23 of the instruction. + Otherwise set it. */ + if (value < 0) + insn &= ~(1 << 23); + else + insn |= 1 << 23; + + /* Place the addend (divided by four) into the first eight + bits of the instruction. */ + insn &= 0xfffffff0; + insn |= addend_abs >> 2; + + /* Update the instruction. */ + md_number_to_chars (buf, insn, INSN_SIZE); + } + break; + case BFD_RELOC_UNUSED: default: as_bad_where (fixP->fx_file, fixP->fx_line, @@ -17957,6 +18405,34 @@ tc_gen_reloc (asection *section, fixS *f case BFD_RELOC_ARM_TLS_LDO32: case BFD_RELOC_ARM_PCREL_CALL: case BFD_RELOC_ARM_PCREL_JUMP: + case BFD_RELOC_ARM_ALU_PC_G0_NC: + case BFD_RELOC_ARM_ALU_PC_G0: + case BFD_RELOC_ARM_ALU_PC_G1_NC: + case BFD_RELOC_ARM_ALU_PC_G1: + case BFD_RELOC_ARM_ALU_PC_G2: + case BFD_RELOC_ARM_LDR_PC_G0: + case BFD_RELOC_ARM_LDR_PC_G1: + case BFD_RELOC_ARM_LDR_PC_G2: + case BFD_RELOC_ARM_LDRS_PC_G0: + case BFD_RELOC_ARM_LDRS_PC_G1: + case BFD_RELOC_ARM_LDRS_PC_G2: + case BFD_RELOC_ARM_LDC_PC_G0: + case BFD_RELOC_ARM_LDC_PC_G1: + case BFD_RELOC_ARM_LDC_PC_G2: + case BFD_RELOC_ARM_ALU_SB_G0_NC: + case BFD_RELOC_ARM_ALU_SB_G0: + case BFD_RELOC_ARM_ALU_SB_G1_NC: + case BFD_RELOC_ARM_ALU_SB_G1: + case BFD_RELOC_ARM_ALU_SB_G2: + case BFD_RELOC_ARM_LDR_SB_G0: + case BFD_RELOC_ARM_LDR_SB_G1: + case BFD_RELOC_ARM_LDR_SB_G2: + case BFD_RELOC_ARM_LDRS_SB_G0: + case BFD_RELOC_ARM_LDRS_SB_G1: + case BFD_RELOC_ARM_LDRS_SB_G2: + case BFD_RELOC_ARM_LDC_SB_G0: + case BFD_RELOC_ARM_LDC_SB_G1: + case BFD_RELOC_ARM_LDC_SB_G2: code = fixp->fx_r_type; break; @@ -18125,6 +18601,12 @@ arm_force_relocation (struct fix * fixp) || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12) return 0; + /* Always leave these relocations for the linker. */ + if ((fixp->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC + && fixp->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2) + || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0) + return 1; + return generic_force_reloc (fixp); } @@ -18202,6 +18684,12 @@ arm_fix_adjustable (fixS * fixP) || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2) return 0; + /* Similarly for group relocations. */ + if ((fixP->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC + && fixP->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2) + || fixP->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0) + return 0; + return 1; } Index: include/elf/arm.h =================================================================== RCS file: /cvs/src/src/include/elf/arm.h,v retrieving revision 1.29 diff -U3 -p -r1.29 arm.h --- include/elf/arm.h 10 Mar 2006 17:20:30 -0000 1.29 +++ include/elf/arm.h 7 Jun 2006 14:42:17 -0000 @@ -169,9 +169,9 @@ START_RELOC_NUMBERS (elf_arm_reloc_type) RELOC_NUMBER (R_ARM_LDRS_SB_G0, 78) RELOC_NUMBER (R_ARM_LDRS_SB_G1, 79) RELOC_NUMBER (R_ARM_LDRS_SB_G2, 80) - RELOC_NUMBER (R_ARM_LDC_G0, 81) - RELOC_NUMBER (R_ARM_LDC_G1, 82) - RELOC_NUMBER (R_ARM_LDC_G2, 83) + RELOC_NUMBER (R_ARM_LDC_SB_G0, 81) + RELOC_NUMBER (R_ARM_LDC_SB_G1, 82) + RELOC_NUMBER (R_ARM_LDC_SB_G2, 83) RELOC_NUMBER (R_ARM_MOVW_BREL_NC, 84) RELOC_NUMBER (R_ARM_MOVT_BREL, 85) RELOC_NUMBER (R_ARM_MOVW_BREL, 86) @@ -221,7 +221,6 @@ START_RELOC_NUMBERS (elf_arm_reloc_type) FAKE_RELOC (R_ARM_GOT32, R_ARM_GOT_BREL) /* 32 bit GOT entry. */ FAKE_RELOC (R_ARM_ROSEGREL32, R_ARM_SBREL31) /* ??? */ FAKE_RELOC (R_ARM_AMP_VCALL9, R_ARM_BREL_ADJ) /* Thumb-something. Not used. */ - FAKE_RELOC (R_ARM_PC13, R_ARM_LDR_PC_G0) /* Unclear whether meaning is different. */ END_RELOC_NUMBERS (R_ARM_max) #ifdef BFD_ARCH_SIZE Index: ld/testsuite/ld-arm/arm-elf.exp =================================================================== RCS file: /cvs/src/src/ld/testsuite/ld-arm/arm-elf.exp,v retrieving revision 1.14 diff -U3 -p -r1.14 arm-elf.exp --- ld/testsuite/ld-arm/arm-elf.exp 15 May 2006 19:57:35 -0000 1.14 +++ ld/testsuite/ld-arm/arm-elf.exp 7 Jun 2006 14:42:18 -0000 @@ -59,6 +59,9 @@ if { ![is_elf_format] || ![istarget "arm # readelf: Apply readelf options on result. Compare with regex (last arg). set armelftests { + {"Group relocations" "-Ttext 0x8000 --section-start zero=0x0 --section-start alpha=0xeef0 --section-start beta=0xffeef0" "" {group-relocs.s} + {{objdump -Dr group-relocs.d}} + "group-relocs"} {"Simple non-PIC shared library" "-shared" "" {arm-lib.s} {{objdump -fdw arm-lib.d} {objdump -Rw arm-lib.r}} "arm-lib.so"} @@ -131,3 +134,8 @@ set armelftests { } run_ld_link_tests $armelftests +run_dump_test "group-relocs-alu-bad" +run_dump_test "group-relocs-ldr-bad" +run_dump_test "group-relocs-ldrs-bad" +run_dump_test "group-relocs-ldc-bad" +
Attachment:
group-relocs-57-83-ldtests.tar.gz
Description: GNU Zip compressed data
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |