summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChao-ying Fu <fu@mips.com>2011-11-23 16:31:14 -0800
committerLogan Chien <loganchien@google.com>2011-11-26 18:51:57 +0800
commit4584cb1a038895f1a9a144bbdb293613373b24ad (patch)
tree195763cd0f84b65be0be21927c5e8a60e43a7df1
parent2050ba7a377e6fb038a36b03cd333fcf91112825 (diff)
downloadlinkloader-4584cb1a038895f1a9a144bbdb293613373b24ad.tar.gz
Fixed AHL calculation.
Change-Id: Iad80b33d9c490088e664c3b7a9e4c91e09b6448c
-rw-r--r--include/impl/ELFObject.hxx48
1 files changed, 39 insertions, 9 deletions
diff --git a/include/impl/ELFObject.hxx b/include/impl/ELFObject.hxx
index e491e15..ceac7be 100644
--- a/include/impl/ELFObject.hxx
+++ b/include/impl/ELFObject.hxx
@@ -438,12 +438,24 @@ relocateMIPS(void *(*find_sym)(void *context, char const *name),
case R_MIPS_HI16:
*inst &= 0xFFFF0000;
- A = A & 0xFFFF;
+ A = (A & 0xFFFF) << 16;
+ // Find the nearest LO16 relocation type after this entry
+ for (size_t j = i + 1; j < reltab->size(); j++) {
+ ELFRelocTy *this_rel = (*reltab)[j];
+ ELFSymbolTy *this_sym = (*symtab)[this_rel->getSymTabIndex()];
+ if (this_rel->getType() == R_MIPS_LO16 && this_sym == sym) {
+ Inst_t *this_inst = (Inst_t *)&(*text)[this_rel->getOffset()];
+ Inst_t this_A = (Inst_t)(uintptr_t)*this_inst;
+ this_A = this_A & 0xFFFF;
+ A += (short)this_A;
+ break;
+ }
+ }
if (strcmp (sym->getName(), "_gp_disp") == 0) {
S = (int)got_address() + GP_OFFSET - (int)P;
sym->setAddress((void *)S);
}
- *inst |= (((S + (A << 16) + (int)0x8000) >> 16) & 0xFFFF);
+ *inst |= (((S + A + (int)0x8000) >> 16) & 0xFFFF);
break;
case R_MIPS_LO16:
@@ -453,10 +465,6 @@ relocateMIPS(void *(*find_sym)(void *context, char const *name),
S = (Inst_t)sym->getAddress();
}
*inst |= ((S + A) & 0xFFFF);
- // We assume the addend of R_MIPS_LO16 won't affect R_MIPS_HI16.
- // If not, we have troubles.
- if (((S + (short)A + (int)0x8000) >> 16) != ((S + (int)0x8000) >> 16))
- rsl_assert("AHL cannot be calculated correctly.");
break;
case R_MIPS_GOT16:
@@ -464,9 +472,31 @@ relocateMIPS(void *(*find_sym)(void *context, char const *name),
{
*inst &= 0xFFFF0000;
A = A & 0xFFFF;
- // FIXME: We just support addend = 0.
- rsl_assert(A == 0 && "R_MIPS_GOT16/R_MIPS_CALL16 addend is not 0.");
- int got_index = search_got((int)rel->getSymTabIndex(), (void *)S,
+ if (rel->getType() == R_MIPS_GOT16) {
+ if (sym->getBindingAttribute() == STB_LOCAL) {
+ A <<= 16;
+
+ // Find the nearest LO16 relocation type after this entry
+ for (size_t j = i + 1; j < reltab->size(); j++) {
+ ELFRelocTy *this_rel = (*reltab)[j];
+ ELFSymbolTy *this_sym = (*symtab)[this_rel->getSymTabIndex()];
+ if (this_rel->getType() == R_MIPS_LO16 && this_sym == sym) {
+ Inst_t *this_inst = (Inst_t *)&(*text)[this_rel->getOffset()];
+ Inst_t this_A = (Inst_t)(uintptr_t)*this_inst;
+ this_A = this_A & 0xFFFF;
+ A += (short)this_A;
+ break;
+ }
+ }
+ }
+ else {
+ rsl_assert(A == 0 && "R_MIPS_GOT16 addend is not 0.");
+ }
+ }
+ else { // R_MIPS_CALL16
+ rsl_assert(A == 0 && "R_MIPS_CALL16 addend is not 0.");
+ }
+ int got_index = search_got((int)rel->getSymTabIndex(), (void *)(S + A),
sym->getBindingAttribute());
int got_offset = (got_index << 2) - GP_OFFSET;
*inst |= (got_offset & 0xFFFF);