1bf58cf51c
The new relocation type RELOLIS handles these instructions: lis RT, ha16[expr] == addis RT, r0, ha16[expr] lis RT, hi16[expr] == addis RT, r0, hi16[expr] RELOLIS stores a 32-bit value in the program text. In this value, the high bit is a ha16 flag, the next 5 bits are the target register RT, and the low bits are a signed 26-bit offset. The linker replaces this value with the lis instruction. The old RELOPPC relocated a ha16/lo16 or hi16/lo16 pair. The new RELOLIS relocates only a ha16 or hi16, so it is no longer necessary to have a matching lo16 in the next instruction. The disadvantage is that RELOLIS has only a signed 26-bit offset, not a 32-bit offset. Switch the assembler to use RELOLIS for ha16 or hi16 and RELO2 for lo16. The li32 instruction still uses the old RELOPPC relocation. This is not the same as my RELOPPC change from my recent mail to tack-devel (https://sourceforge.net/p/tack/mailman/message/35651528/). This commit is on a different branch. Here I am throwing away my RELOPPC change and instead trying RELOLIS.
76 lines
1.5 KiB
C
76 lines
1.5 KiB
C
static int hl_token;
|
|
static expr_t hl_expr;
|
|
|
|
void no_hl(void) {
|
|
hl_token = 0;
|
|
}
|
|
|
|
word_t eval_hl(expr_t* expr, int token)
|
|
{
|
|
word_t val = expr->val;
|
|
uint16_t hi = val >> 16;
|
|
uint16_t lo = val & 0xffff;
|
|
|
|
hl_token = token;
|
|
hl_expr = *expr;
|
|
|
|
switch (token) {
|
|
case OP_HI: /* hi16[expr] */
|
|
return hi;
|
|
case OP_HA: /* ha16[expr]*/
|
|
/*
|
|
* If the low half will be treated as a signed value,
|
|
* then values greater than 0x7fff will cause the high
|
|
* half to have 1 subtracted from it; so we apply an
|
|
* adjustment here.
|
|
*/
|
|
if (lo > 0x7fff)
|
|
hi++;
|
|
return hi;
|
|
case OP_LO: /* lo16[expr] */
|
|
return lo;
|
|
}
|
|
}
|
|
|
|
void emit_hl(word_t in)
|
|
{
|
|
word_t reg;
|
|
int type;
|
|
|
|
switch (hl_token) {
|
|
case OP_HI: /* hi16[expr] */
|
|
case OP_HA: /* ha16[expr] */
|
|
if (PASS_RELO && (hl_expr.typ & S_TYP) != S_ABS) {
|
|
/*
|
|
* RELOLIS only works with lis _, _ (same as
|
|
* addis _, r0, _). Check if instruction
|
|
* isn't addis or register RA isn't r0.
|
|
*/
|
|
if ((in & 0xfc1f0000) != (0x3c000000))
|
|
serror("relocation only works with lis");
|
|
|
|
/*
|
|
* High bit: ha16 flag
|
|
* Next 5 bits: register RT
|
|
* Low 26 bits: signed offset
|
|
*/
|
|
fit(fitx(hl_expr.val, 26));
|
|
newrelo(hl_expr.typ, RELOLIS | FIXUPFLAGS);
|
|
reg = (in >> 21) & 0x1f;
|
|
in = (hl_token == OP_HA) << 31;
|
|
in |= reg << 26;
|
|
in |= hl_expr.val & 0x03ffffff;
|
|
}
|
|
break;
|
|
case OP_LO: /* lo16[expr] */
|
|
if (PASS_RELO && (hl_expr.typ & S_TYP) != S_ABS) {
|
|
DOTVAL += 2;
|
|
newrelo(hl_expr.typ, RELO2 | FIXUPFLAGS);
|
|
DOTVAL -= 2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
emit4(in);
|
|
}
|