mirror of
https://github.com/rui314/mold.git
synced 2024-10-26 13:10:46 +03:00
[LoongArch] Fix symbol value computation for the extreme code model
The LoongArch extreme code model uses the following instructions to materialize a 64-bit value in a regiter. pcalau12i $t1, %pc_hi20(g2) addi.d $t0, $zero, %pc_lo12(g2) lu32i.d $t0, %pc64_lo20(g2) lu52i.d $t0, $t0, %pc64_hi12(g2) The previous relocation formula expected that `page(pc)` would be consistent for all the instructions, but this assumption is incorrect if the instruction sequence crosses a 4 KiB boundary. Now, the LoongArch psABI requires that the machine instructions must be consecutive, and the relocations for lu32.d and lu52i.d uses `page(pc - 8)` and `page(pc - 16)` instead of `page(pc)`. This psABI change gave me an impression that the LoongArch's extreme code model was poorly designed and inadequately tested. If these instructions must be consecutive, only a single relocation referring to the beginning of the instructions would suffice, which relocates all the following four instructions at once. Maybe we do not need to support the relocations for the extreme code model because the code model was buggy at the spec level, which suggests that no one is using them. But I'm not sure if it is safe to remove them, so let's just follow the psABI change.
This commit is contained in:
parent
9e0c1c81dd
commit
d6d8d2e494
@ -51,7 +51,7 @@ static u64 hi20(u64 val, u64 pc) {
|
||||
return bits(page(val + 0x800) - page(pc), 31, 12);
|
||||
}
|
||||
|
||||
static u64 hi64(u64 val, u64 pc) {
|
||||
static u64 higher20(u64 val, u64 pc) {
|
||||
// A PC-relative 64-bit address is materialized with the following
|
||||
// instructions for the large code model:
|
||||
//
|
||||
@ -65,21 +65,15 @@ static u64 hi64(u64 val, u64 pc) {
|
||||
// ADDI.D adds a sign-extended 12 bit value to a register. LU32I.D and
|
||||
// LU52I.D simply set bits to [51:31] and to [63:53], respectively.
|
||||
//
|
||||
// Compensating all the sign-extensions is a bit complicated.
|
||||
u64 x = page(val) - page(pc);
|
||||
if (val & 0x800)
|
||||
x += 0x1000 - 0x1'0000'0000;
|
||||
if (x & 0x8000'0000)
|
||||
x += 0x1'0000'0000;
|
||||
return x;
|
||||
}
|
||||
|
||||
static u64 higher20(u64 val, u64 pc) {
|
||||
return bits(hi64(val, pc), 51, 32);
|
||||
// Compensating all the sign-extensions is a bit complicated. The
|
||||
// psABI gave the following formula.
|
||||
val = val + 0x8000'0000 + ((val & 0x800) ? (0x1000 - 0x1'0000'0000) : 0);
|
||||
return bits(page(val) - page(pc - 8), 51, 32);
|
||||
}
|
||||
|
||||
static u64 highest12(u64 val, u64 pc) {
|
||||
return bits(hi64(val, pc), 63, 52);
|
||||
val = val + 0x8000'0000 + ((val & 0x800) ? (0x1000 - 0x1'0000'0000) : 0);
|
||||
return bits(page(val) - page(pc - 12), 63, 52);
|
||||
}
|
||||
|
||||
static void write_k12(u8 *loc, u32 val) {
|
||||
|
Loading…
Reference in New Issue
Block a user