Skip to content

Commit 1e59740

Browse files
committed
[SPARC64] Preserve rd of TLS *_ADD relocations during optimization
GCC might decide to put the result of the operation in another register, so remove hardcodings of %o0 as the destination register (`rd` field).
1 parent 5fb6d8a commit 1e59740

File tree

1 file changed

+11
-2
lines changed

1 file changed

+11
-2
lines changed

src/arch-sparc64.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,8 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
390390
}
391391
} else {
392392
u32 rs2 = bits(*(ub32 *)loc, 4, 0);
393-
*(ub32 *)loc = 0x9001'c000 | rs2; // add %g7, %reg, %o0
393+
u32 rd = bits(*(ub32 *)loc, 29, 25);
394+
*(ub32 *)loc = 0x9001'c000 | (rd << 25) | rs2; // add %g7, %reg, %rd
394395
}
395396
break;
396397
case R_SPARC_TLS_GD_CALL:
@@ -420,7 +421,8 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
420421
// do nothing
421422
} else {
422423
u32 rs2 = bits(*(ub32 *)loc, 4, 0);
423-
*(ub32 *)loc = 0x9021'c000 | rs2; // sub %g7, %reg, %o0
424+
u32 rd = bits(*(ub32 *)loc, 29, 25);
425+
*(ub32 *)loc = 0x9021'c000 | (rd << 25) | rs2; // sub %g7, %reg, %rd
424426
}
425427
break;
426428
case R_SPARC_TLS_LDM_CALL:
@@ -429,6 +431,13 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
429431
*(ub32 *)loc |= bits(addr + A - P, 31, 2);
430432
} else {
431433
*(ub32 *)loc = 0x0100'0000; // nop
434+
435+
// If the argument to __tls_get_addr is set in the delay slot of the call,
436+
// turn the delay slot instruction into a nop too.
437+
u32 ds_rd = bits(*(ub32 *)(loc + 4), 29, 25);
438+
if (ds_rd == 8) { // rd is %o0
439+
*(ub32 *)(loc + 4) = 0x0100'0000; // nop
440+
}
432441
}
433442
break;
434443
case R_SPARC_TLS_LDO_HIX22:

0 commit comments

Comments
 (0)