This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] ARM: Add support for thumb1 PCROP relocations.
- From: mickael guene <mickael dot guene at st dot com>
- To: "binutils at sourceware dot org" <binutils at sourceware dot org>
- Date: Mon, 23 Nov 2015 09:43:26 +0100
- Subject: [PATCH] ARM: Add support for thumb1 PCROP relocations.
- Authentication-results: sourceware.org; auth=none
Hi all,
This is a proposal for a patch that implements the new ARM relocations
needed to support execute-only code segment for thumb1 code sequences.
Some STM32 MCUs implement a security feature called 'Proprietary Code
Read-Out Protection' aka PCROP that forbids data read access to some
code areas (only fetch access is allowed).
This protection prevents usage of literal pools (since one cannot load
data from code sections), so compilers have to use specific code
sequence to generate constants. This is particularly a problem to
generate symbol addresses.
For armv7-m architecture compilers can generate movt/movw pair
instructions relying on R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS
relocations support.
For armv6-m there is currently no possibility to generate such symbol
addresses.
This is why the ARM ABI defines four new relocations that allow
symbol address generation in armv6-m architecture using a sequence of
movs/adds/lsls instructions.
This patch implements this feature in gas and bfd.
Unit tests have be written to check correct implementation for both
gas and bfd.
No regressions have been observed for arm-linux-gnueabi,
arm-linux-gnueabihf, arm-none-eabi, arm-none-nacl and
armeb-linux-gnueabihf targets on 64 bits linux host.
Changelogs:
include/ChangeLog:
2015-11-17 Mickael Guene <mickael.guene@st.com>
* elf/arm.h: Add new arm relocations.
bfd/ChangeLog:
2015-11-17 Mickael Guene <mickael.guene@st.com>
* bfd-in2.h: Regenerate.
* reloc.c: Add new relocations.
* libbfd.h (bfd_reloc_code_real_names): Add new relocations display
names.
* elf32-arm.c (elf32_arm_howto_table_1): Add HOWTO for new relocations.
(elf32_arm_reloc_map): Add bfd/arm mapping for new relocations.
(elf32_arm_final_link_relocate): Implement new relocations resolution.
gas/ChangeLog:
2015-11-17 Mickael Guene <mickael.guene@st.com>
* config/tc-arm.c (group_reloc_table): Add mapping between gas syntax
and new relocations.
(do_t_add_sub): Keep new relocations for add operand.
(do_t_mov_cmp): Keep new relocations for mov operand.
(insns): Use 'shifter operand with possible group relocation' operand
parse code for movs operand.
(md_apply_fix): Implement mov and add encoding when new relocations
on them.
(tc_gen_reloc): Add new relocations.
(arm_fix_adjustable): Since offset has a limited range ([0:255]) we
disable adjust_reloc_syms() for new relocations.
gas/testsuite/ChangeLog:
2015-11-17 Mickael Guene <mickael.guene@st.com>
* gas/arm/adds-thumb1-reloc-local.d: New
* gas/arm/adds-thumb1-reloc-local.s: New
* gas/arm/movs-thumb1-reloc-local.d: New
* gas/arm/movs-thumb1-reloc-local.s: New
ld/testsuite/ChangeLog:
2015-11-17 Mickael Guene <mickael.guene@st.com>
* ld-arm/arm-elf.exp (armelftests_common): Add new relocations tests.
* ld-arm/thumb1-adds.d: New
* ld-arm/thumb1-adds.s: New
* ld-arm/thumb1-movs.d: New
* ld-arm/thumb1-movs.s: New
>From 0f43cd955385c615ea91de88c4a09a586d400dbf Mon Sep 17 00:00:00 2001
From: Mickael Guene <mickael.guene@st.com>
Date: Fri, 9 Oct 2015 10:01:33 +0200
Subject: [PATCH] Add support for thumb1 pcrop relocations.
To support thumb1 execute-only code we need to support four new
relocations (R_ARM_THM_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G1_NC,
R_ARM_THM_ALU_ABS_G2_NC and R_ARM_THM_ALU_ABS_G3_NC).
These relocations allow the static linker to finalize construction
of symbol address.
Typical sequence of code to get address of the symbol foo is then
the following :
movs r3, #:high_high:#foo
lsls r3, #8
adds r3, #:high_low:#foo
lsls r3, #8
adds r3, #:low_high:#foo
lsls r3, #8
adds r3, #:low_low:#foo
This will give following sequence of text and relocations after
assembly :
4: 2300 movs r3, #0
4: R_ARM_THM_ALU_ABS_G3_NC foo
6: 021b lsls r3, r3, #8
8: 3300 adds r3, #0
8: R_ARM_THM_ALU_ABS_G2_NC foo
a: 021b lsls r3, r3, #8
c: 3300 adds r3, #0
c: R_ARM_THM_ALU_ABS_G1_NC foo
e: 021b lsls r3, r3, #8
10: 3300 adds r3, #0
10: R_ARM_THM_ALU_ABS_G0_NC foo
---
bfd/bfd-in2.h | 6 ++
bfd/elf32-arm.c | 87 ++++++++++++++++++-
bfd/libbfd.h | 4 +
bfd/reloc.c | 11 +++
gas/config/tc-arm.c | 107 ++++++++++++++++++++++--
gas/testsuite/gas/arm/adds-thumb1-reloc-local.d | 16 ++++
gas/testsuite/gas/arm/adds-thumb1-reloc-local.s | 13 +++
gas/testsuite/gas/arm/movs-thumb1-reloc-local.d | 16 ++++
gas/testsuite/gas/arm/movs-thumb1-reloc-local.s | 13 +++
include/elf/arm.h | 5 ++
ld/testsuite/ld-arm/arm-elf.exp | 6 ++
ld/testsuite/ld-arm/thumb1-adds.d | 38 +++++++++
ld/testsuite/ld-arm/thumb1-adds.s | 42 ++++++++++
ld/testsuite/ld-arm/thumb1-movs.d | 38 +++++++++
ld/testsuite/ld-arm/thumb1-movs.s | 42 ++++++++++
15 files changed, 437 insertions(+), 7 deletions(-)
create mode 100644 gas/testsuite/gas/arm/adds-thumb1-reloc-local.d
create mode 100644 gas/testsuite/gas/arm/adds-thumb1-reloc-local.s
create mode 100644 gas/testsuite/gas/arm/movs-thumb1-reloc-local.d
create mode 100644 gas/testsuite/gas/arm/movs-thumb1-reloc-local.s
create mode 100644 ld/testsuite/ld-arm/thumb1-adds.d
create mode 100644 ld/testsuite/ld-arm/thumb1-adds.s
create mode 100644 ld/testsuite/ld-arm/thumb1-movs.d
create mode 100644 ld/testsuite/ld-arm/thumb1-movs.s
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index bca5181..77d57f1 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3469,6 +3469,12 @@ pc-relative or some form of GOT-indirect relocation. */
/* ARM support for STT_GNU_IFUNC. */
BFD_RELOC_ARM_IRELATIVE,
+/* Thumb1 relocations to support execute-only code. */
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC,
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC,
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC,
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC,
+
/* These relocs are only used within the ARM assembler. They are not
(at present) written to any object files. */
BFD_RELOC_ARM_IMMEDIATE,
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 9fd5720..a3cd1fd 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -1689,6 +1689,60 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
0x00000000, /* src_mask */
0x00000000, /* dst_mask */
FALSE), /* pcrel_offset */
+ EMPTY_HOWTO (130),
+ EMPTY_HOWTO (131),
+ HOWTO (R_ARM_THM_ALU_ABS_G0_NC,/* type. */
+ 0, /* rightshift. */
+ 1, /* size (0 = byte, 1 = short, 2 = long). */
+ 16, /* bitsize. */
+ FALSE, /* pc_relative. */
+ 0, /* bitpos. */
+ complain_overflow_bitfield,/* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_ARM_THM_ALU_ABS_G0_NC",/* name. */
+ FALSE, /* partial_inplace. */
+ 0x00000000, /* src_mask. */
+ 0x00000000, /* dst_mask. */
+ FALSE), /* pcrel_offset. */
+ HOWTO (R_ARM_THM_ALU_ABS_G1_NC,/* type. */
+ 0, /* rightshift. */
+ 1, /* size (0 = byte, 1 = short, 2 = long). */
+ 16, /* bitsize. */
+ FALSE, /* pc_relative. */
+ 0, /* bitpos. */
+ complain_overflow_bitfield,/* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_ARM_THM_ALU_ABS_G1_NC",/* name. */
+ FALSE, /* partial_inplace. */
+ 0x00000000, /* src_mask. */
+ 0x00000000, /* dst_mask. */
+ FALSE), /* pcrel_offset. */
+ HOWTO (R_ARM_THM_ALU_ABS_G2_NC,/* type. */
+ 0, /* rightshift. */
+ 1, /* size (0 = byte, 1 = short, 2 = long). */
+ 16, /* bitsize. */
+ FALSE, /* pc_relative. */
+ 0, /* bitpos. */
+ complain_overflow_bitfield,/* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_ARM_THM_ALU_ABS_G2_NC",/* name. */
+ FALSE, /* partial_inplace. */
+ 0x00000000, /* src_mask. */
+ 0x00000000, /* dst_mask. */
+ FALSE), /* pcrel_offset. */
+ HOWTO (R_ARM_THM_ALU_ABS_G3_NC,/* type. */
+ 0, /* rightshift. */
+ 1, /* size (0 = byte, 1 = short, 2 = long). */
+ 16, /* bitsize. */
+ FALSE, /* pc_relative. */
+ 0, /* bitpos. */
+ complain_overflow_bitfield,/* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_ARM_THM_ALU_ABS_G3_NC",/* name. */
+ FALSE, /* partial_inplace. */
+ 0x00000000, /* src_mask. */
+ 0x00000000, /* dst_mask. */
+ FALSE), /* pcrel_offset. */
};
/* 160 onwards: */
@@ -1889,7 +1943,11 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
{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},
- {BFD_RELOC_ARM_V4BX, R_ARM_V4BX}
+ {BFD_RELOC_ARM_V4BX, R_ARM_V4BX},
+ {BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC, R_ARM_THM_ALU_ABS_G3_NC},
+ {BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC, R_ARM_THM_ALU_ABS_G2_NC},
+ {BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC, R_ARM_THM_ALU_ABS_G1_NC},
+ {BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G0_NC}
};
static reloc_howto_type *
@@ -10406,6 +10464,33 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
}
return bfd_reloc_ok;
+ case R_ARM_THM_ALU_ABS_G0_NC:
+ case R_ARM_THM_ALU_ABS_G1_NC:
+ case R_ARM_THM_ALU_ABS_G2_NC:
+ case R_ARM_THM_ALU_ABS_G3_NC:
+ {
+ const int shift_array[4] = {0, 8, 16, 24};
+ bfd_vma insn = bfd_get_16 (input_bfd, hit_data);
+ bfd_vma addr = value;
+ int shift = shift_array[r_type - R_ARM_THM_ALU_ABS_G0_NC];
+
+ /* compute address. */
+ if (globals->use_rel)
+ signed_addend = insn & 0xff;
+ addr += signed_addend;
+ if (branch_type == ST_BRANCH_TO_THUMB)
+ addr |= 1;
+ /* clean imm8 insn. */
+ insn &= 0xff00;
+ /* and update with correct part of address. */
+ insn |= (addr >> shift) & 0xff;
+ /* update insn. */
+ bfd_put_16 (input_bfd, insn, hit_data);
+ }
+
+ *unresolved_reloc_p = FALSE;
+ return bfd_reloc_ok;
+
default:
return bfd_reloc_notsupported;
}
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 1c54d0f..84f7244 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1525,6 +1525,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_ARM_LDC_SB_G2",
"BFD_RELOC_ARM_V4BX",
"BFD_RELOC_ARM_IRELATIVE",
+ "BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC",
+ "BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC",
+ "BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC",
+ "BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC",
"BFD_RELOC_ARM_IMMEDIATE",
"BFD_RELOC_ARM_ADRL_IMMEDIATE",
"BFD_RELOC_ARM_T32_IMMEDIATE",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index ba73ef7..55ccfaa 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3250,6 +3250,17 @@ ENUMDOC
ARM support for STT_GNU_IFUNC.
ENUM
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ENUMX
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC
+ENUMX
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC
+ENUMX
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC
+ENUMDOC
+ Thumb1 relocations to support execute-only code.
+
+ENUM
BFD_RELOC_ARM_IMMEDIATE
ENUMX
BFD_RELOC_ARM_ADRL_IMMEDIATE
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 2ab8bbe..567e904 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -5305,7 +5305,28 @@ static struct group_reloc_table_entry group_reloc_table[] =
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 */
+ BFD_RELOC_ARM_LDC_SB_G2 }, /* LDC */
+ /* Absolute thumb alu relocations. */
+ { "low_low",
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC,/* ALU. */
+ 0, /* LDR. */
+ 0, /* LDRS. */
+ 0 }, /* LDC. */
+ { "low_high",
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC,/* ALU. */
+ 0, /* LDR. */
+ 0, /* LDRS. */
+ 0 }, /* LDC. */
+ { "high_low",
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC,/* ALU. */
+ 0, /* LDR. */
+ 0, /* LDRS. */
+ 0 }, /* LDC. */
+ { "high_high",
+ BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC,/* ALU. */
+ 0, /* LDR. */
+ 0, /* LDRS. */
+ 0 } }; /* 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
@@ -10234,7 +10255,9 @@ do_t_add_sub (void)
{
inst.instruction = THUMB_OP16(opcode);
inst.instruction |= (Rd << 4) | Rs;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+ if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
if (inst.size_req != 2)
inst.relax = opcode;
}
@@ -11585,9 +11608,12 @@ do_t_mov_cmp (void)
inst.instruction = THUMB_OP16 (opcode);
inst.instruction |= Rn << 8;
if (inst.size_req == 2)
- inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
- else
- inst.relax = opcode;
+ {
+ if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+ } else
+ inst.relax = opcode;
}
else
{
@@ -18409,7 +18435,7 @@ static const struct asm_opcode insns[] =
CL("cmnp", 170f000, 2, (RR, SH), cmp),
tCE("mov", 1a00000, _mov, 2, (RR, SH), mov, t_mov_cmp),
- tC3("movs", 1b00000, _movs, 2, (RR, SH), mov, t_mov_cmp),
+ tC3("movs", 1b00000, _movs, 2, (RR, SHG), mov, t_mov_cmp),
tCE("mvn", 1e00000, _mvn, 2, (RR, SH), mov, t_mvn_tst),
tC3("mvns", 1f00000, _mvns, 2, (RR, SH), mov, t_mvn_tst),
@@ -22942,6 +22968,65 @@ md_apply_fix (fixS * fixP,
}
return;
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
+ gas_assert (!fixP->fx_done);
+ if (!seg->use_rela_p)
+ {
+ bfd_vma insn;
+ bfd_boolean is_mov;
+ bfd_vma encoded_addend = value;
+
+ /* check that addend can be encoded. */
+ if (value < 0 || value > 255)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("the offset 0x%08lX is not representable"),
+ (unsigned long) encoded_addend);
+
+ /* Extract the instruction. */
+ insn = md_chars_to_number (buf, THUMB_SIZE);
+ is_mov = (insn & 0xf800) == 0x2000;
+
+ /* Encode insn. */
+ if (is_mov)
+ {
+ insn |= encoded_addend;
+ } else {
+ int rd, rs;
+
+ /* Extract the instruction. */
+ /* Encoding is the following
+ 0x8000 SUB
+ 0x00F0 Rd
+ 0x000F Rs
+ */
+ /* The following conditions must be true :
+ * - ADD
+ * - Rd == Rs
+ * - Rd <= 7
+ */
+ rd = (insn >> 4) & 0xf;
+ rs = insn & 0xf;
+ if ((insn & 0x8000) || (rd != rs) || rd > 7)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Unable to process relocation for thumb opcode: %lx",
+ (unsigned long) insn);
+
+ /* Encode as ADD immediate8 thumb 1 code. */
+ insn = 0x3000 | (rd << 8);
+
+ /* Place the encoded addend into the first 8 bits of the
+ instruction. */
+ insn |= encoded_addend;
+ }
+
+ /* Update the instruction. */
+ md_number_to_chars (buf, insn, THUMB_SIZE);
+ }
+ break;
+
case BFD_RELOC_ARM_ALU_PC_G0_NC:
case BFD_RELOC_ARM_ALU_PC_G0:
case BFD_RELOC_ARM_ALU_PC_G1_NC:
@@ -23279,6 +23364,10 @@ tc_gen_reloc (asection *section, fixS *fixp)
case BFD_RELOC_ARM_LDC_SB_G1:
case BFD_RELOC_ARM_LDC_SB_G2:
case BFD_RELOC_ARM_V4BX:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
+ case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
code = fixp->fx_r_type;
break;
@@ -23581,6 +23670,12 @@ arm_fix_adjustable (fixS * fixP)
|| fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT_PCREL)
return FALSE;
+ /* BFD_RELOC_ARM_THUMB_ALU_ABS_Gx_NC relocations have VERY limited
+ offsets, so keep these symbols. */
+ if (fixP->fx_r_type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && fixP->fx_r_type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+ return FALSE;
+
return TRUE;
}
#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
diff --git a/gas/testsuite/gas/arm/adds-thumb1-reloc-local.d b/gas/testsuite/gas/arm/adds-thumb1-reloc-local.d
new file mode 100644
index 0000000..190f0ab
--- /dev/null
+++ b/gas/testsuite/gas/arm/adds-thumb1-reloc-local.d
@@ -0,0 +1,16 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#skip: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+#name: ADDS relocations against local symbols for armv6s-m
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0[0-9a-f]+ <[^>]+> 3000 adds r0, #0
+ 0: R_ARM_THM_ALU_ABS_G3_NC bar
+0[0-9a-f]+ <[^>]+> 3000 adds r0, #0
+ 2: R_ARM_THM_ALU_ABS_G2_NC bar
+0[0-9a-f]+ <[^>]+> 3000 adds r0, #0
+ 4: R_ARM_THM_ALU_ABS_G1_NC bar
+0[0-9a-f]+ <[^>]+> 3000 adds r0, #0
+ 6: R_ARM_THM_ALU_ABS_G0_NC bar
+#...
diff --git a/gas/testsuite/gas/arm/adds-thumb1-reloc-local.s b/gas/testsuite/gas/arm/adds-thumb1-reloc-local.s
new file mode 100644
index 0000000..65e921c
--- /dev/null
+++ b/gas/testsuite/gas/arm/adds-thumb1-reloc-local.s
@@ -0,0 +1,13 @@
+.arch armv6s-m
+.text
+.syntax unified
+.thumb
+foo:
+adds r0, #:high_high:#bar
+adds r0, #:high_low:#bar
+adds r0, #:low_high:#bar
+adds r0, #:low_low:#bar
+
+.space 0x10000
+
+bar:
diff --git a/gas/testsuite/gas/arm/movs-thumb1-reloc-local.d b/gas/testsuite/gas/arm/movs-thumb1-reloc-local.d
new file mode 100644
index 0000000..3febca3
--- /dev/null
+++ b/gas/testsuite/gas/arm/movs-thumb1-reloc-local.d
@@ -0,0 +1,16 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#skip: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+#name: MOVS relocations against local symbols for armv6s-m
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0[0-9a-f]+ <[^>]+> 2000 movs r0, #0
+ 0: R_ARM_THM_ALU_ABS_G3_NC bar
+0[0-9a-f]+ <[^>]+> 2000 movs r0, #0
+ 2: R_ARM_THM_ALU_ABS_G2_NC bar
+0[0-9a-f]+ <[^>]+> 2000 movs r0, #0
+ 4: R_ARM_THM_ALU_ABS_G1_NC bar
+0[0-9a-f]+ <[^>]+> 2000 movs r0, #0
+ 6: R_ARM_THM_ALU_ABS_G0_NC bar
+#...
diff --git a/gas/testsuite/gas/arm/movs-thumb1-reloc-local.s b/gas/testsuite/gas/arm/movs-thumb1-reloc-local.s
new file mode 100644
index 0000000..868cab5
--- /dev/null
+++ b/gas/testsuite/gas/arm/movs-thumb1-reloc-local.s
@@ -0,0 +1,13 @@
+.arch armv6s-m
+.text
+.syntax unified
+.thumb
+foo:
+movs r0, #:high_high:#bar
+movs r0, #:high_low:#bar
+movs r0, #:low_high:#bar
+movs r0, #:low_low:#bar
+
+.space 0x10000
+
+bar:
diff --git a/include/elf/arm.h b/include/elf/arm.h
index 34afdfd..92101c0 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -231,6 +231,11 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
RELOC_NUMBER (R_ARM_ME_TOO, 128) /* obsolete */
RELOC_NUMBER (R_ARM_THM_TLS_DESCSEQ ,129)
+ RELOC_NUMBER (R_ARM_THM_ALU_ABS_G0_NC,132)
+ RELOC_NUMBER (R_ARM_THM_ALU_ABS_G1_NC,133)
+ RELOC_NUMBER (R_ARM_THM_ALU_ABS_G2_NC,134)
+ RELOC_NUMBER (R_ARM_THM_ALU_ABS_G3_NC,135)
+
RELOC_NUMBER (R_ARM_IRELATIVE, 160)
/* Extensions? R=read-only? */
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 3c8cc68..36bcaae 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -207,6 +207,12 @@ set armelftests_common {
"" {pcrel-shared.s}
{{readelf -dr pcrel-shared.rd}}
"pcrel-shared.so"}
+ {"MOVS thumb1 relocations" "-static -T arm.ld" "" "" {thumb1-movs.s}
+ {{objdump -dw thumb1-movs.d}}
+ "thumb1-movs"}
+ {"ADDS thumb1 relocations" "-static -T arm.ld" "" "" {thumb1-adds.s}
+ {{objdump -dw thumb1-adds.d}}
+ "thumb1-adds"}
}
set armelftests_nonacl {
diff --git a/ld/testsuite/ld-arm/thumb1-adds.d b/ld/testsuite/ld-arm/thumb1-adds.d
new file mode 100644
index 0000000..68ef68e
--- /dev/null
+++ b/ld/testsuite/ld-arm/thumb1-adds.d
@@ -0,0 +1,38 @@
+
+.*: file format.*
+
+Disassembly of section .text:
+
+00008000 <[^>]*>:
+ 8000: 3012 adds r0, #18
+ 8002: 3134 adds r1, #52 ; 0x34
+ 8004: 3280 adds r2, #128 ; 0x80
+ 8006: 3301 adds r3, #1
+ 8008: 3401 adds r4, #1
+ 800a: 3500 adds r5, #0
+ 800c: 3600 adds r6, #0
+ 800e: 3700 adds r7, #0
+
+00008010 <[^>]*>:
+ 8010: 3012 adds r0, #18
+ 8012: 3100 adds r1, #0
+ 8014: 3200 adds r2, #0
+ 8016: 33ca adds r3, #202 ; 0xca
+ 8018: 3700 adds r7, #0
+ 801a: 3634 adds r6, #52 ; 0x34
+ 801c: 3581 adds r5, #129 ; 0x81
+ 801e: 3423 adds r4, #35 ; 0x23
+
+00008020 <[^>]*>:
+ 8020: 01 .byte 0x01
+
+00008021 <[^>]*>:
+ 8021: 02 .byte 0x02
+
+Disassembly of section .far:
+
+12340000 <[^>]*>:
+12340000: 3000 adds r0, #0
+12340002: 3100 adds r1, #0
+12340004: 3200 adds r2, #0
+12340006: 3301 adds r3, #1
diff --git a/ld/testsuite/ld-arm/thumb1-adds.s b/ld/testsuite/ld-arm/thumb1-adds.s
new file mode 100644
index 0000000..8009d7d
--- /dev/null
+++ b/ld/testsuite/ld-arm/thumb1-adds.s
@@ -0,0 +1,42 @@
+ .text
+ .arch armv6s-m
+ .syntax unified
+ .global _start
+ .thumb_func
+ .type _start, %function
+ .type thumb1, %function
+_start:
+thumb1:
+ adds r0, #:high_high:#thumb3
+ adds r1, #:high_low:#thumb3
+ adds r2, #:low_high:#thumb1
+ adds r3, #:low_low:#thumb1
+ adds r4, #:low_low:#thumb3
+ adds r5, #:low_high:#thumb3
+ adds r6, #:high_low:#thumb1
+ adds r7, #:high_high:#thumb1
+ .thumb_func
+ .type thumb2, %function
+thumb2:
+ adds r0, #:high_high:#thumb3
+ adds r1, #:high_low:#(var2 + 1)
+ adds r2, #:low_high:#(thumb3 + 255)
+ adds r3, #:low_low:#(var1 + 0xaa)
+ adds r7, #:high_high:#var1 + 4
+ adds r6, #:high_low:#thumb3
+ adds r5, #:low_high:#var2 + 0xff
+ adds r4, #:low_low:#var2 - (-2)
+var1:
+ .byte 1
+var2:
+ .byte 2
+
+ .section .far, "ax", %progbits
+ .thumb_func
+ .type thumb3, %function
+thumb3:
+ adds r0, #:high_high:#thumb1
+ adds r1, #:high_low:#thumb2
+ adds r2, #:low_high:#thumb3
+ adds r3, #:low_low:#thumb1
+
diff --git a/ld/testsuite/ld-arm/thumb1-movs.d b/ld/testsuite/ld-arm/thumb1-movs.d
new file mode 100644
index 0000000..6a72bc1
--- /dev/null
+++ b/ld/testsuite/ld-arm/thumb1-movs.d
@@ -0,0 +1,38 @@
+
+.*: file format.*
+
+Disassembly of section .text:
+
+00008000 <[^>]*>:
+ 8000: 2012 movs r0, #18
+ 8002: 2134 movs r1, #52 ; 0x34
+ 8004: 2280 movs r2, #128 ; 0x80
+ 8006: 2301 movs r3, #1
+ 8008: 2401 movs r4, #1
+ 800a: 2500 movs r5, #0
+ 800c: 2600 movs r6, #0
+ 800e: 2700 movs r7, #0
+
+00008010 <[^>]*>:
+ 8010: 2012 movs r0, #18
+ 8012: 2100 movs r1, #0
+ 8014: 2281 movs r2, #129 ; 0x81
+ 8016: 2320 movs r3, #32
+ 8018: 2700 movs r7, #0
+ 801a: 2600 movs r6, #0
+ 801c: 2581 movs r5, #129 ; 0x81
+ 801e: 2422 movs r4, #34 ; 0x22
+
+00008020 <[^>]*>:
+ 8020: 01 .byte 0x01
+
+00008021 <[^>]*>:
+ 8021: 02 .byte 0x02
+
+Disassembly of section .far:
+
+12340000 <[^>]*>:
+12340000: 2000 movs r0, #0
+12340002: 2100 movs r1, #0
+12340004: 2200 movs r2, #0
+12340006: 2301 movs r3, #1
diff --git a/ld/testsuite/ld-arm/thumb1-movs.s b/ld/testsuite/ld-arm/thumb1-movs.s
new file mode 100644
index 0000000..06fa7fb
--- /dev/null
+++ b/ld/testsuite/ld-arm/thumb1-movs.s
@@ -0,0 +1,42 @@
+ .text
+ .arch armv6s-m
+ .syntax unified
+ .global _start
+ .thumb_func
+ .type _start, %function
+ .type thumb1, %function
+_start:
+thumb1:
+ movs r0, #:high_high:#thumb3
+ movs r1, #:high_low:#thumb3
+ movs r2, #:low_high:#thumb1
+ movs r3, #:low_low:#thumb1
+ movs r4, #:low_low:#thumb3
+ movs r5, #:low_high:#thumb3
+ movs r6, #:high_low:#thumb1
+ movs r7, #:high_high:#thumb1
+ .thumb_func
+ .type thumb2, %function
+thumb2:
+ movs r0, #:high_high:#(thumb3 + 0)
+ movs r1, #:high_low:#(thumb2 + 1)
+ movs r2, #:low_high:#(var1 + 255)
+ movs r3, #:low_low:#var1
+ movs r7, #:high_high:#var1 + 4
+ movs r6, #:high_low:#var2
+ movs r5, #:low_high:#var2 + 0xff
+ movs r4, #:low_low:#var2 - (-1)
+var1:
+ .byte 1
+var2:
+ .byte 2
+
+ .section .far, "ax", %progbits
+ .thumb_func
+ .type thumb3, %function
+thumb3:
+ movs r0, #:high_high:#thumb1
+ movs r1, #:high_low:#thumb2
+ movs r2, #:low_high:#thumb3
+ movs r3, #:low_low:#thumb1
+
--
2.6.2