Print this page
10267 ld and GCC disagree about i386 local dynamic TLS
@@ -413,15 +413,26 @@
* 0x0c
*/
0x90
};
-static uchar_t tlsinstr_gd_ie_movgs[] = {
+static uchar_t tlsinstr_ld_le_movgs[] = {
/*
- * movl %gs:0x0,%eax
+ * 0x00 movl %gs:0x0,%eax
*/
- 0x65, 0xa1, 0x00, 0x00, 0x00, 00
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00,
+};
+
+/*
+ * 0x00 nopl 0(%eax,%eax) -- the intel recommended 5-byte nop
+ * See Intel® 64 and IA-32 Architectures Software Developer’s Manual
+ * Volume 2B: Instruction Set Reference, M-U
+ * Table 4-12, Recommended Multi-Byte Sequence of NOP Instruction
+ */
+static uchar_t tlsinstr_nop5[] = {
+
+ 0x0f, 0x1f, 0x44, 0x00, 0x00
};
#define TLS_GD_IE_MOV 0x8b /* movl opcode */
#define TLS_GD_IE_POP 0x58 /* popl + reg */
@@ -526,11 +537,12 @@
return (FIX_RELOC);
case R_386_TLS_GD_PLT:
case R_386_PLT32:
/*
- * Fixup done via the TLS_GD relocation
+ * Fixup done via the TLS_GD/TLS_LDM relocation processing
+ * and ld_reloc_plt() handling __tls_get_addr().
*/
DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH,
R_386_NONE, arsp, ld_reloc_sym_name));
return (FIX_DONE);
@@ -540,21 +552,14 @@
/*
* Transition:
* call __tls_get_addr()
* to:
- * nop
- * nop
- * nop
- * nop
- * nop
- */
- *(offset - 1) = TLS_NOP;
- *(offset) = TLS_NOP;
- *(offset + 1) = TLS_NOP;
- *(offset + 2) = TLS_NOP;
- *(offset + 3) = TLS_NOP;
+ * nopl 0x0(%eax,%eax)
+ */
+ (void) memcpy(offset - 1, tlsinstr_nop5,
+ sizeof (tlsinstr_nop5));
return (FIX_DONE);
case R_386_TLS_LDM:
DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH,
R_386_NONE, arsp, ld_reloc_sym_name));
@@ -567,12 +572,21 @@
*
* to:
*
* 0x00 movl %gs:0, %eax
*/
- (void) memcpy(offset - 2, tlsinstr_gd_ie_movgs,
- sizeof (tlsinstr_gd_ie_movgs));
+ (void) memcpy(offset - 2, tlsinstr_ld_le_movgs,
+ sizeof (tlsinstr_ld_le_movgs));
+
+ /*
+ * We implicitly treat this as if a R_386_TLS_LDM_PLT for the
+ * __tls_get_addr call followed it as the GNU compiler
+ * doesn't generate one. This is safe, because if one _does_
+ * exist we'll just write the nop again.
+ */
+ (void) memcpy(offset + 4, tlsinstr_nop5,
+ sizeof (tlsinstr_nop5));
return (FIX_DONE);
case R_386_TLS_LDO_32:
/*
* Instructions: