diff options
author | Shih-wei Liao <sliao@google.com> | 2012-03-02 11:01:54 -0800 |
---|---|---|
committer | Shih-wei Liao <sliao@google.com> | 2012-03-02 11:11:20 -0800 |
commit | 2a7f249060179fdcb49f240bdf349c4e7b896084 (patch) | |
tree | 8ee2fd7878c32ab2e92f6e96b61cff85b3c87561 | |
parent | 141f4435692cc53db032525e1cc602c3b417c42e (diff) | |
download | linkloader-2a7f249060179fdcb49f240bdf349c4e7b896084.tar.gz |
Support:T.
Change-Id: Ib54a93ea6d6a63df710679b70aab67feb578e67d
-rw-r--r-- | include/impl/ELFObject.hxx | 120 | ||||
-rw-r--r-- | include/impl/ELFSectionRelTable.hxx | 3 |
2 files changed, 107 insertions, 16 deletions
diff --git a/include/impl/ELFObject.hxx b/include/impl/ELFObject.hxx index 24ec1b2..eba2dd1 100644 --- a/include/impl/ELFObject.hxx +++ b/include/impl/ELFObject.hxx @@ -143,24 +143,54 @@ relocateARM(void *(*find_sym)(void *context, char const *name), Inst_t P = (Inst_t)(int64_t)inst; Inst_t A = 0; Inst_t S = (Inst_t)(int64_t)sym->getAddress(EM_ARM); + Inst_t T = 0; + + if (sym->isConcreteFunc() && (sym->getValue() & 0x1)) { + T = 1; + } switch (rel->getType()) { default: rsl_assert(0 && "Not implemented relocation type."); break; + // Unknown to me. + case R_ARM_NONE: + { + *inst = S|T; + } + case R_ARM_ABS32: { A = *inst; - *inst = (S+A); + *inst = (S + A) | T; } break; // FIXME: Predefine relocation codes. case R_ARM_CALL: + case R_ARM_THM_CALL: { #define SIGN_EXTEND(x, l) (((x)^(1<<((l)-1)))-(1<<(l-1))) - A = (Inst_t)(int64_t)SIGN_EXTEND(*inst & 0xFFFFFF, 24); + if (rel->getType() == R_ARM_CALL) { + A = (Inst_t)(int64_t)SIGN_EXTEND(*inst & 0xFFFFFF, 24); + A <<= 2; + } + else { + // Hack for two 16bit. + *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16); + Inst_t s = (*inst >> 26) & 0x1u, // 26 + u = (*inst >> 16) & 0x3FFu, // 25-16 + l = *inst & 0x7FFu, // 10-0 + j1 = (*inst >> 13) & 0x1u, // 13 + j2 = (*inst >> 11) & 0x1u; // 11 + Inst_t i1 = (~(j1 ^ s)) & 0x1u, + i2 = (~(j2 ^ s)) & 0x1u; + // [31-25][24][23][22][21-12][11-1][0] + // 0 s i1 i2 u l 0 + A = SIGN_EXTEND((s << 23) | (i1 << 22) | (i2 << 21) | (u << 11) | l, 24); + A <<= 1; + } #undef SIGN_EXTEND void *callee_addr = sym->getAddress(EM_ARM); @@ -214,19 +244,52 @@ relocateARM(void *(*find_sym)(void *context, char const *name), //LOGI("Function %s: using stub %p\n", sym->getName(), stub); S = (uint32_t)(uintptr_t)stub; - // Relocate the R_ARM_CALL relocation type - uint32_t result = (S >> 2) - (P >> 2) + A; + if (rel->getType() == R_ARM_CALL) { + // Relocate the R_ARM_CALL relocation type + uint32_t result = (S + A - P) >> 2; - if (result > 0x007fffff && result < 0xff800000) { - rsl_assert(0 && "Stub is still too far"); - abort(); + if (result > 0x007FFFFF && result < 0xFF800000) { + rsl_assert(0 && "Stub is still too far"); + abort(); + } + + *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000); } + else { + // Relocate the R_ARM_THM_CALL relocation type + uint32_t result = (S + A - P) >> 1; + + if (result > 0x007FFFFF && result < 0xFF800000) { + rsl_assert(0 && "Stub is still too far"); + abort(); + } - *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000); + // Rewrite instruction to BLX. + *inst &= 0xF800C000u; + // [31-25][24][23][22][21-12][11-1][0] + // 0 s i1 i2 u l 0 + Inst_t s = (result >> 23) & 0x1u, // 26 + u = (result >> 11) & 0x3FFu, // 25-16 + // For BLX, bit [0] is 0. + l = result & 0x7FEu, // 10-0 + i1 = (result >> 22) & 0x1u, + i2 = (result >> 21) & 0x1u; + Inst_t j1 = ((~i1) ^ s) & 0x01u, // 13 + j2 = ((~i2) ^ s) & 0x01u; // 11 + *inst |= s << 26; + *inst |= u << 16; + *inst |= l; + *inst |= j1 << 13; + *inst |= j2 << 11; + // Hack for two 16bit. + *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16); + } } break; case R_ARM_MOVT_ABS: case R_ARM_MOVW_ABS_NC: + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: { if (S==0 && sym->getType() == STT_NOTYPE) { @@ -237,16 +300,43 @@ relocateARM(void *(*find_sym)(void *context, char const *name), S = (Inst_t)(uintptr_t)ext_sym; sym->setAddress(ext_sym); } - if (rel->getType() == R_ARM_MOVT_ABS) { + if (rel->getType() == R_ARM_MOVT_ABS + || rel->getType() == R_ARM_THM_MOVT_ABS) { S >>= 16; } - // No need sign extend. - A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF); - uint32_t result = (S+A); - *inst = (((result) & 0xF000) << 4) | - ((result) & 0xFFF) | - (*inst & 0xFFF0F000); + if (rel->getType() == R_ARM_MOVT_ABS + || rel->getType() == R_ARM_MOVW_ABS_NC) { + // No need sign extend. + A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF); + uint32_t result = (S + A); + *inst = (((result) & 0xF000) << 4) | + ((result) & 0xFFF) | + (*inst & 0xFFF0F000); + } + else { + // Hack for two 16bit. + *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16); + // imm16: [19-16][26][14-12][7-0] + A = (((*inst >> 4) & 0xF000u) | + ((*inst >> 15) & 0x0800u) | + ((*inst >> 4) & 0x0700u) | + ( *inst & 0x00FFu)); + uint32_t result; + if (rel->getType() == R_ARM_THM_MOVT_ABS) { + result = (S + A); + } else { + result = (S + A) | T; + } + // imm16: [19-16][26][14-12][7-0] + *inst &= 0xFBF08F00u; + *inst |= (result & 0xF000u) << 4; + *inst |= (result & 0x0800u) << 15; + *inst |= (result & 0x0700u) << 4; + *inst |= (result & 0x00FFu); + // Hack for two 16bit. + *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16); + } } break; } diff --git a/include/impl/ELFSectionRelTable.hxx b/include/impl/ELFSectionRelTable.hxx index 4c2417d..d5d04a2 100644 --- a/include/impl/ELFSectionRelTable.hxx +++ b/include/impl/ELFSectionRelTable.hxx @@ -98,7 +98,8 @@ getMaxNumStubs(ELFObjectTy const *obj) const { for (size_t i = 0; i < size(); ++i) { ELFRelocTy *rel = table[i]; - if (rel->getType() == R_ARM_CALL) { + if (rel->getType() == R_ARM_CALL || + rel->getType() == R_ARM_THM_CALL) { sym_index_set.insert(rel->getSymTabIndex()); } } |