Simplify MIPS relocations. Add RELS2 (for generic high-word relocations). Add
support for MIPS branch-and-jump relocations.
This commit is contained in:
parent
0d8d98fd0f
commit
b3b7c684c6
4
h/out.h
4
h/out.h
|
@ -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. */
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue