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]

[PATCH] ARM group relocations


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.

OK for mainline, after that has been approved?

Mark

--

ChangeLog:

2006-06-07 Mark Shinwell <shinwell@codesourcery.com>

	* 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/ChangeLog:

2006-06-07 Mark Shinwell <shinwell@codesourcery.com>

	* 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/ChangeLog:

2006-06-07 Mark Shinwell <shinwell@codesourcery.com>

	* 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/ChangeLog:

2006-06-07 Mark Shinwell <shinwell@codesourcery.com>

	* 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/ChangeLog:

2006-06-07 Mark Shinwell <shinwell@codesourcery.com>

	* 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]