===================================================================
@@ -12571,7 +12571,23 @@ legitimize_tls_address (rtx x, enum tls_
off = gen_const_mem (Pmode, off);
set_mem_alias_set (off, ix86_GOT_alias_set ());
- if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
+ if (TARGET_64BIT && TARGET_SUN_TLS)
+ {
+ /* The SUN linker took the AMD64 TLS spec literally
+ and can only handle %rax as destination of the
+ initial executable code sequence. */
+
+ rtx rax = gen_rtx_REG (Pmode, AX_REG);
+
+ base = get_thread_pointer (false);
+ emit_insn (gen_rtx_SET (VOIDmode, rax, base));
+ emit_insn (gen_add_tls_addr_di_sun (rax, rax, off));
+
+ dest = gen_reg_rtx (Pmode);
+ emit_move_insn (dest, rax);
+ return dest;
+ }
+ else if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
{
base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
off = force_reg (Pmode, off);
===================================================================
@@ -93,6 +93,7 @@
UNSPEC_TLS_GD
UNSPEC_TLS_LD_BASE
UNSPEC_TLSDESC
+ UNSPEC_TLSDESC_SUN
;; Other random patterns
UNSPEC_SCAS
@@ -12661,6 +12664,31 @@
;; Segment register for the thread base ptr load
(define_mode_attr tp_seg [(SI "gs") (DI "fs")])
+;; The SUN linker took the AMD64 TLS spec literally and can only handle
+;; %rax as the destination of the initial executable code sequence.
+(define_insn "*load_tp_di_sun"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (unspec:DI [(const_int 0)] UNSPEC_TP))]
+ "TARGET_64BIT && TARGET_SUN_TLS"
+ "mov{q}\t{%%fs:0, %0|%0, QWORD PTR fs:0}"
+ [(set_attr "type" "imov")
+ (set_attr "modrm" "0")
+ (set_attr "length" "7")
+ (set_attr "memory" "load")
+ (set_attr "imm_disp" "false")])
+
+(define_insn "add_tls_addr_di_sun"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (plus:DI
+ (match_operand:DI 1 "register_operand" "0")
+ (match_operand:DI 2 "memory_operand" "m")))
+ (clobber (reg:CC FLAGS_REG))
+ (unspec [(const_int 0)] UNSPEC_TLSDESC_SUN)]
+ "TARGET_64BIT && TARGET_SUN_TLS"
+ "add{q}\t{%2, %0|%0, %2}";
+ [(set_attr "type" "alu")
+ (set_attr "mode" "DI")])
+
;; Load and add the thread base pointer from %gs:0.
(define_insn "*load_tp_<mode>"
[(set (match_operand:P 0 "register_operand" "=r")