mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kern: implement support for applying relr relocations
This commit is contained in:
parent
f93aea4c06
commit
11c02e22e0
2 changed files with 94 additions and 14 deletions
|
@ -114,6 +114,23 @@ namespace ams::kern::init::Elf::Elf64 {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Relr {
|
||||||
|
private:
|
||||||
|
Xword m_info;
|
||||||
|
public:
|
||||||
|
constexpr ALWAYS_INLINE bool IsLocation() const {
|
||||||
|
return (m_info & 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Xword GetLocation() const {
|
||||||
|
return m_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Xword GetBitmap() const {
|
||||||
|
return m_info >> 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum DynamicTag {
|
enum DynamicTag {
|
||||||
DT_NULL = 0,
|
DT_NULL = 0,
|
||||||
DT_RELA = 7,
|
DT_RELA = 7,
|
||||||
|
@ -121,6 +138,10 @@ namespace ams::kern::init::Elf::Elf64 {
|
||||||
DT_REL = 17,
|
DT_REL = 17,
|
||||||
DT_RELENT = 19,
|
DT_RELENT = 19,
|
||||||
|
|
||||||
|
DT_RELRSZ = 35,
|
||||||
|
DT_RELR = 36,
|
||||||
|
DT_RELRENT = 37,
|
||||||
|
|
||||||
DT_RELACOUNT = 0x6ffffff9,
|
DT_RELACOUNT = 0x6ffffff9,
|
||||||
DT_RELCOUNT = 0x6ffffffa
|
DT_RELCOUNT = 0x6ffffffa
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,10 +21,13 @@ namespace ams::kern::init::Elf {
|
||||||
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
||||||
uintptr_t dyn_rel = 0;
|
uintptr_t dyn_rel = 0;
|
||||||
uintptr_t dyn_rela = 0;
|
uintptr_t dyn_rela = 0;
|
||||||
|
uintptr_t dyn_relr = 0;
|
||||||
uintptr_t rel_count = 0;
|
uintptr_t rel_count = 0;
|
||||||
uintptr_t rela_count = 0;
|
uintptr_t rela_count = 0;
|
||||||
|
uintptr_t relr_sz = 0;
|
||||||
uintptr_t rel_ent = 0;
|
uintptr_t rel_ent = 0;
|
||||||
uintptr_t rela_ent = 0;
|
uintptr_t rela_ent = 0;
|
||||||
|
uintptr_t relr_ent = 0;
|
||||||
|
|
||||||
/* Iterate over all tags, identifying important extents. */
|
/* Iterate over all tags, identifying important extents. */
|
||||||
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
||||||
|
@ -35,24 +38,38 @@ namespace ams::kern::init::Elf {
|
||||||
case DT_RELA:
|
case DT_RELA:
|
||||||
dyn_rela = base_address + cur_entry->GetPtr();
|
dyn_rela = base_address + cur_entry->GetPtr();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELR:
|
||||||
|
dyn_relr = base_address + cur_entry->GetPtr();
|
||||||
|
break;
|
||||||
case DT_RELENT:
|
case DT_RELENT:
|
||||||
rel_ent = cur_entry->GetValue();
|
rel_ent = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
case DT_RELAENT:
|
case DT_RELAENT:
|
||||||
rela_ent = cur_entry->GetValue();
|
rela_ent = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELRENT:
|
||||||
|
relr_ent = cur_entry->GetValue();
|
||||||
|
break;
|
||||||
case DT_RELCOUNT:
|
case DT_RELCOUNT:
|
||||||
rel_count = cur_entry->GetValue();
|
rel_count = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
case DT_RELACOUNT:
|
case DT_RELACOUNT:
|
||||||
rela_count = cur_entry->GetValue();
|
rela_count = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELRSZ:
|
||||||
|
relr_sz = cur_entry->GetValue();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply all Rel relocations */
|
/* Apply all Rel relocations */
|
||||||
for (size_t i = 0; i < rel_count; i++) {
|
if (rel_count > 0) {
|
||||||
const auto &rel = *reinterpret_cast<const Elf::Rel *>(dyn_rel + rel_ent * i);
|
/* Check that the rel relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_rel != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(rel_ent == sizeof(Elf::Rel));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rel_count; ++i) {
|
||||||
|
const auto &rel = reinterpret_cast<const Elf::Rel *>(dyn_rel)[i];
|
||||||
|
|
||||||
/* Only allow architecture-specific relocations. */
|
/* Only allow architecture-specific relocations. */
|
||||||
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
||||||
|
@ -61,10 +78,16 @@ namespace ams::kern::init::Elf {
|
||||||
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
|
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
|
||||||
*target_address += base_address;
|
*target_address += base_address;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply all Rela relocations. */
|
/* Apply all Rela relocations. */
|
||||||
for (size_t i = 0; i < rela_count; i++) {
|
if (rela_count > 0) {
|
||||||
const auto &rela = *reinterpret_cast<const Elf::Rela *>(dyn_rela + rela_ent * i);
|
/* Check that the rela relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_rela != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(rela_ent == sizeof(Elf::Rela));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rela_count; ++i) {
|
||||||
|
const auto &rela = reinterpret_cast<const Elf::Rela *>(dyn_rela)[i];
|
||||||
|
|
||||||
/* Only allow architecture-specific relocations. */
|
/* Only allow architecture-specific relocations. */
|
||||||
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
||||||
|
@ -75,6 +98,42 @@ namespace ams::kern::init::Elf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apply all Relr relocations. */
|
||||||
|
if (relr_sz >= sizeof(Elf::Relr)) {
|
||||||
|
/* Check that the relr relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_relr != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(relr_ent == sizeof(Elf::Relr));
|
||||||
|
|
||||||
|
const size_t relr_count = relr_sz / sizeof(Elf::Relr);
|
||||||
|
|
||||||
|
Elf::Addr *where = nullptr;
|
||||||
|
for (size_t i = 0; i < relr_count; ++i) {
|
||||||
|
const auto &relr = reinterpret_cast<const Elf::Relr *>(dyn_relr)[i];
|
||||||
|
|
||||||
|
if (relr.IsLocation()) {
|
||||||
|
/* Update location. */
|
||||||
|
where = reinterpret_cast<Elf::Addr *>(base_address + relr.GetLocation());
|
||||||
|
|
||||||
|
/* Apply the relocation. */
|
||||||
|
*(where++) += base_address;
|
||||||
|
} else {
|
||||||
|
/* Get the bitmap. */
|
||||||
|
u64 bitmap = relr.GetBitmap();
|
||||||
|
|
||||||
|
/* Apply all relocations. */
|
||||||
|
while (bitmap != 0) {
|
||||||
|
const u64 next = util::CountTrailingZeros(bitmap);
|
||||||
|
bitmap &= ~(static_cast<u64>(1) << next);
|
||||||
|
where[next] += base_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
where += BITSIZEOF(bitmap) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
|
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
|
||||||
for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) {
|
for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) {
|
||||||
(*(void (**)())(cur_entry))();
|
(*(void (**)())(cur_entry))();
|
||||||
|
|
Loading…
Reference in a new issue