Simplify MIPS relocations. Add RELS2 (for generic high-word relocations). Add

support for MIPS branch-and-jump relocations.
This commit is contained in:
David Given 2018-09-09 12:23:59 +02:00
parent 0d8d98fd0f
commit b3b7c684c6
4 changed files with 75 additions and 8 deletions

View file

@ -68,9 +68,9 @@ struct outname {
#define RELOPPC 4 /* PowerPC 26-bit address */ #define RELOPPC 4 /* PowerPC 26-bit address */
#define RELOPPC_LIS 5 /* PowerPC lis */ #define RELOPPC_LIS 5 /* PowerPC lis */
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */ #define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
#define RELOMIPS 7 /* MIPS, low half of word or other*/ #define RELOMIPS 7 /* MIPS */
#define RELOMIPSHI 8 /* MIPS, high half of word */
#define RELS2 0x1000 /* shift result right 16 bits before writing back */
#define RELPC 0x2000 /* pc relative */ #define RELPC 0x2000 /* pc relative */
#define RELBR 0x4000 /* High order byte lowest address. */ #define RELBR 0x4000 /* High order byte lowest address. */
#define RELWR 0x8000 /* High order word lowest address. */ #define RELWR 0x8000 /* High order word lowest address. */

View file

@ -76,8 +76,8 @@
0, OP_LI, 0, "li", 0, OP_LI, 0, "li",
0, OP_LA, 0, "la", 0, OP_LA, 0, "la",
0, HI, RELOMIPSHI, "hi", 0, HI, RELO2|RELS2,"hi",
0, LO, RELOMIPS, "lo", 0, LO, RELO2, "lo",
#include "tokens.y" #include "tokens.y"

View file

@ -24,10 +24,10 @@
word_t val = $4.val; word_t val = $4.val;
if (type != S_ABS) if (type != S_ABS)
newrelo($4.typ, RELOMIPSHI | FIXUPFLAGS); newrelo($4.typ, RELO2 | RELS2 | FIXUPFLAGS);
emit4(0x3c000000 | (reg<<16) | (val>>16)); /* lui reg, value */ emit4(0x3c000000 | (reg<<16) | (val>>16)); /* lui reg, value */
if (type != S_ABS) if (type != S_ABS)
newrelo($4.typ, RELOMIPS | FIXUPFLAGS); newrelo($4.typ, RELO2 | FIXUPFLAGS);
emit4(0x34000000 | (reg<<16) | (reg<<21) | (val & 0xffff)); /* ori reg, reg, value */ emit4(0x34000000 | (reg<<16) | (reg<<21) | (val & 0xffff)); /* ori reg, reg, value */
} }

View file

@ -179,6 +179,30 @@ static uint32_t get_lis_valu(char *addr, uint16_t type)
return valu; return valu;
} }
/* RELOMIPS is used for j and b instructions only. */
static uint32_t get_mips_valu(char* addr)
{
uint32_t value = read4(addr, 0);
switch (value >> 26)
{
case 2: /* j */
case 3: /* jal */
case 29: /* jalx */
/* Unsigned 26-bit payload. */
value = value & ((1<<26)-1);
break;
default: /* assume everything else is a b, there are lots */
/* Signed 16-bit payload. */
value = ((int32_t)value << 16) >> 16;
break;
}
/* The value has two implicit zero bits on the bottom. */
value <<= 2;
return value;
}
/* /*
* The bits in type indicate how many bytes the value occupies and what * The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte. * significance should be attributed to each byte.
@ -198,8 +222,10 @@ static uint32_t getvalu(char* addr, uint16_t type)
return get_lis_valu(addr, type); return get_lis_valu(addr, type);
case RELOVC4: case RELOVC4:
return get_vc4_valu(addr); return get_vc4_valu(addr);
case RELOMIPS:
return get_mips_valu(addr);
default: default:
fatal("bad relocation type %x", type & RELSZ); fatal("can't read relocation type %x", type & RELSZ);
} }
/* NOTREACHED */ /* NOTREACHED */
} }
@ -369,6 +395,36 @@ static void put_lis_valu(char* addr, uint32_t value, uint16_t type)
write4(opcode, addr, type); write4(opcode, addr, type);
} }
/* RELOMIPS is used for j and b instructions only. */
static void put_mips_valu(char* addr, uint32_t value)
{
uint32_t opcode = read4(addr, 0);
/* The two bottom zero bits are implicit. */
if (value & 3)
fatal("invalid MIPS relocation value 0x%x", value);
value >>= 2;
switch (value >> 26)
{
case 2: /* j */
case 3: /* jal */
case 29: /* jalx */
/* Unsigned 26-bit payload. */
value = value & ((1<<26)-1);
opcode = opcode & ~((1<<26)-1);
break;
default: /* assume everything else is a b, there are lots */
/* Signed 16-bit payload. */
value = value & ((1<<16)-1);
opcode = opcode & ~((1<<16)-1);
break;
}
write4(opcode | value, addr, 0);
}
/* /*
* The bits in type indicate how many bytes the value occupies and what * The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte. * significance should be attributed to each byte.
@ -396,8 +452,11 @@ static putvalu(uint32_t valu, char* addr, uint16_t type)
case RELOVC4: case RELOVC4:
put_vc4_valu(addr, valu); put_vc4_valu(addr, valu);
break; break;
case RELOMIPS:
put_mips_valu(addr, valu);
break;
default: default:
fatal("bad relocation type %x", type & RELSZ); fatal("can't write relocation type %x", type & RELSZ);
} }
} }
@ -506,6 +565,14 @@ relocate(head, emit, names, relo, off)
if (relo->or_type & RELPC) if (relo->or_type & RELPC)
valu -= relorig[sectindex].org_size+outsect[sectindex].os_base; valu -= relorig[sectindex].org_size+outsect[sectindex].os_base;
/*
* If RELS2 is set, right shift the value by sixteen bits; this
* allows 32-bit values to be fixed up as a high word and a low
* word.
*/
if (relo->or_type & RELS2)
valu >>= 16;
/* /*
* Now put the value back. * Now put the value back.
*/ */