Permalink
Browse files

3337 x64 link-editor is painfully literal-minded about TLS

Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
  • Loading branch information...
1 parent 90a1a13 commit 49f9b365248ee858ee91baa36eab27c5200f6dca @richlowe richlowe committed Nov 3, 2012
@@ -514,6 +514,23 @@ static uchar_t tlsinstr_ld_le[] = {
0x00, 0x00, 0x00, 0x00
};
+#define REX_B 0x1
+#define REX_X 0x2
+#define REX_R 0x4
+#define REX_W 0x8
+#define REX_PREFIX 0x40
+
+#define REX_RW (REX_PREFIX | REX_R | REX_W)
+#define REX_BW (REX_PREFIX | REX_B | REX_W)
+#define REX_BRW (REX_PREFIX | REX_B | REX_R | REX_W)
+
+#define REG_ESP 0x4
+
+#define INSN_ADDMR 0x03 /* addq mem,reg */
+#define INSN_ADDIR 0x81 /* addq imm,reg */
+#define INSN_MOVMR 0x8b /* movq mem,reg */
+#define INSN_MOVIR 0xc7 /* movq imm,reg */
+#define INSN_LEA 0x8d /* leaq mem,reg */
static Fixupret
tls_fixups(Ofl_desc *ofl, Rel_desc *arsp)
@@ -526,6 +543,10 @@ tls_fixups(Ofl_desc *ofl, Rel_desc *arsp)
(uintptr_t)_elf_getxoff(arsp->rel_isdesc->is_indata) +
(uintptr_t)RELAUX_GET_OSDESC(arsp)->os_outdata->d_buf);
+ /*
+ * Note that in certain of the original insn sequences below, the
+ * instructions are not necessarily adjacent
+ */
if (sdp->sd_ref == REF_DYN_NEED) {
/*
* IE reference model
@@ -605,35 +626,88 @@ tls_fixups(Ofl_desc *ofl, Rel_desc *arsp)
(void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le));
return (FIX_RELOC);
- case R_AMD64_GOTTPOFF:
+ case R_AMD64_GOTTPOFF: {
/*
* IE -> LE
*
- * Transition:
- * 0x00 movq %fs:0, %rax
- * 0x09 addq x@gottopoff(%rip), %rax
- * 0x10
+ * Transition 1:
+ * movq %fs:0, %reg
+ * addq x@gottpoff(%rip), %reg
* To:
- * 0x00 movq %fs:0, %rax
- * 0x09 leaq x@tpoff(%rax), %rax
- * 0x10
+ * movq %fs:0, %reg
+ * leaq x@tpoff(%reg), %reg
+ *
+ * Transition (as a special case):
+ * movq %fs:0, %r12/%rsp
+ * addq x@gottpoff(%rip), %r12/%rsp
+ * To:
+ * movq %fs:0, %r12/%rsp
+ * addq x@tpoff(%rax), %r12/%rsp
+ *
+ * Transition 2:
+ * movq x@gottpoff(%rip), %reg
+ * movq %fs:(%reg), %reg
+ * To:
+ * movq x@tpoff(%reg), %reg
+ * movq %fs:(%reg), %reg
*/
+ Conv_inv_buf_t inv_buf;
+ uint8_t reg; /* Register */
+
+ offset -= 3;
+
+ reg = offset[2] >> 3; /* Encoded dest. reg. operand */
+
DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH,
R_AMD64_TPOFF32, arsp, ld_reloc_sym_name));
arsp->rel_rtype = R_AMD64_TPOFF32;
arsp->rel_raddend = 0;
/*
- * Adjust 'offset' to beginning of instruction sequence.
+ * This is transition 2, and the special case of form 1 where
+ * a normal transition would index %rsp or %r12 and need a SIB
+ * byte in the leaq for which we lack space
*/
- offset -= 12;
+ if ((offset[1] == INSN_MOVMR) ||
+ ((offset[1] == INSN_ADDMR) && (reg == REG_ESP))) {
+ /*
+ * If we needed an extra bit of MOD.reg to refer to
+ * this register as the dest of the original movq we
+ * need an extra bit of MOD.rm to refer to it in the
+ * dest of the replacement movq or addq.
+ */
+ if (offset[0] == REX_RW)
+ offset[0] = REX_BW;
- /*
- * Same code sequence used in the GD -> LE transition.
- */
- (void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le));
- return (FIX_RELOC);
+ offset[1] = (offset[1] == INSN_MOVMR) ?
+ INSN_MOVIR : INSN_ADDIR;
+ offset[2] = 0xc0 | reg;
+ return (FIX_RELOC);
+ } else if (offset[1] == INSN_ADDMR) {
+ /*
+ * If we needed an extra bit of MOD.reg to refer to
+ * this register in the dest of the addq we need an
+ * extra bit of both MOD.reg and MOD.rm to refer to it
+ * in the source and dest of the leaq
+ */
+ if (offset[0] == REX_RW)
+ offset[0] = REX_BRW;
+
+ offset[1] = INSN_LEA;
+ offset[2] = 0x80 | (reg << 3) | reg;
+
+ return (FIX_RELOC);
+ }
+
+ ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_BADTLSINS),
+ conv_reloc_amd64_type(arsp->rel_rtype, 0, &inv_buf),
+ arsp->rel_isdesc->is_file->ifl_name,
+ ld_reloc_sym_name(arsp),
+ arsp->rel_isdesc->is_name,
+ EC_OFF(arsp->rel_roffset));
+ return (FIX_ERROR);
+ }
case R_AMD64_TLSLD:
/*
* LD -> LE
@@ -0,0 +1,87 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2012, Richard Lowe.
+
+include $(SRC)/Makefile.master
+
+# We have to use GCC, and only GCC. The best way is to ask cw(1) which GCC to use.
+CC_CMD = $(ONBLD_TOOLS)/bin/$(MACH)/cw -_gcc -_compiler
+CC = $(CC_CMD:sh)
+CFLAGS = -O1 -m64
+
+LINK.c = env LD_ALTEXEC=$(PROTO)/usr/bin/amd64/ld $(CC) $(CFLAGS) -o $@ $^
+COMPILE.c = $(CC) $(CFLAGS) -c -o $@ $^
+COMPILE.s = $(CC) $(CFLAGS) -c -o $@ $^
+
+.KEEP_STATE:
+
+install default: all
+
+.c.o:
+ $(COMPILE.c)
+
+.s.o:
+ $(COMPILE.s)
+
+# A basic use of TLS that uses the movq m/r --> movq i/r variant
+PROGS += style2
+STYLE2OBJS = style2.o
+style2: $(STYLE2OBJS)
+ $(LINK.c)
+
+# A copy of style2 that uses %r13 in the TLS sequence, and thus excercises the
+# REX transitions of the movq mem,reg -> movq imm,reg variant.
+PROGS += style2-with-r13
+STYLE2R13OBJS = style2-with-r13.o
+style2-with-r13: $(STYLE2R13OBJS)
+ $(LINK.c)
+
+# A copy of style2 that uses %r12 in the TLS sequence, so we can verify that
+# it is _not_ special to this variant
+PROGS += style2-with-r12
+STYLE2R12OBJS = style2-with-r12.o
+style2-with-r12: $(STYLE2R12OBJS)
+ $(LINK.c)
+
+# A copy of style2 that has a R_AMD64_GOTTPOFF relocation with a bad insn sequence
+STYLE2BADNESSOBJS = style2-with-badness.o
+style2-with-badness: $(STYLE2BADNESSOBJS)
+ -$(LINK.c)
+
+# A basic use of TLS that uses the addq mem/reg --> leaq mem,reg variant
+PROGS += style1
+STYLE1OBJS = style1-main.o style1-func.o
+style1: $(STYLE1OBJS)
+ $(LINK.c)
+
+# A copy of style1-func that uses %r13 in the TLS sequence and thus excercises
+# the REX transitions. of the addq mem,reg --> leaq mem,reg variant
+PROGS += style1-with-r13
+STYLE1R13OBJS = style1-main.o style1-func-with-r13.o
+style1-with-r13: $(STYLE1R13OBJS)
+ $(LINK.c)
+
+# A copy of style1-func that uses %r12 to test the addq mem,reg --> addq imm,reg variant
+PROGS += style1-with-r12
+STYLE1R12OBJS = style1-main.o style1-func-with-r12.o
+style1-with-r12: $(STYLE1R12OBJS)
+ $(LINK.c)
+
+all: $(PROGS)
+
+clobber clean:
+ rm -f $(PROGS) $(STYLE1OBJS) $(STYLE1R13OBJS) $(STYLE1R12OBJS) \
+ $(STYLE2OBJS) $(STYLE2R13OBJS) $(STYLE2R12OBJS) $(STYLE2BADNESSOBJS)
+
+fail: style2-with-badness FRC
+
+FRC:
@@ -0,0 +1,9 @@
+This tests the x64 link-editor's handling of Initial Executable TLS sequences.
+
+The original C source files are in orig/ but unused, since we need to avoid
+any changes to the compiler influencing our tests.
+
+ % ksh x64-ie-test.sh /path/to/proto/root
+ pass: addq-->leaq 1
+ ...
+ pass: bad insn sequence
@@ -0,0 +1,24 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+
+extern __thread char *foo, *bar;
+
+void
+func()
+{
+ printf("foo: %p bar: %p\n", &foo, &bar);
+}
@@ -0,0 +1,29 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+
+extern void func();
+
+__thread char *foo = "foo";
+__thread char *bar = "bar";
+
+int
+main(void)
+{
+ printf("foo: %p bar: %p\n", &foo, &bar);
+ func();
+ return (0);
+}
@@ -0,0 +1,25 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+
+__thread char *foo __attribute__((tls_model("initial-exec"))) = "foo";
+
+int
+main(void)
+{
+ printf("foo: %p\n", &foo);
+ return (0);
+}
@@ -0,0 +1,39 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+ .section .rodata.str1.1,"aMS",@progbits,1
+.LC0:
+ .string "foo: %p bar: %p\n"
+ .text
+.globl func
+ .type func, @function
+func:
+.LFB0:
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ movq %fs:0, %r12
+ movq %r12, %rdx
+ addq bar@GOTTPOFF(%rip), %rdx
+ addq foo@GOTTPOFF(%rip), %r12
+ movq %r12, %rsi
+ movl $.LC0, %edi
+ movl $0, %eax
+ call printf
+ leave
+ ret
+.LFE0:
+ .size func, .-func
@@ -0,0 +1,38 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+ .section .rodata.str1.1,"aMS",@progbits,1
+.LC0:
+ .string "foo: %p bar: %p\n"
+ .text
+.globl func
+ .type func, @function
+func:
+.LFB0:
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ movq %fs:0, %r13
+ movq %r13, %rdx
+ addq bar@GOTTPOFF(%rip), %rdx
+ addq foo@GOTTPOFF(%rip), %r13
+ movq %r13, %rsi
+ movl $.LC0, %edi
+ movl $0, %eax
+ call printf
+ leave
+ ret
+.LFE0:
+ .size func, .-func
Oops, something went wrong.

0 comments on commit 49f9b36

Please sign in to comment.