fix(patcher): keep zero-vaddr code segment and fix stub entry vaddr
This commit is contained in:
parent
f84e67f2b1
commit
8236d4e1a2
|
|
@ -11,7 +11,6 @@ public:
|
|||
|
||||
private:
|
||||
[[nodiscard]] bool _isSceSpecificSegment(std::uint32_t type) const;
|
||||
[[nodiscard]] bool _isNullPageLoad(const Domain::ProgramHeader& ph) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void ProgramHeaderLayoutBuilder::_writeProgramHeader(std::vector<std::uint8_t>&
|
|||
Domain::ProgramHeader ProgramHeaderLayoutBuilder::_makeLoadHeader(std::uint64_t offset, std::uint64_t vaddr, std::uint64_t size) const {
|
||||
Domain::ProgramHeader ph{};
|
||||
ph.Type = PT_LOAD;
|
||||
ph.Flags = PF_R | PF_W;
|
||||
ph.Flags = PF_R | PF_W | PF_X;
|
||||
ph.Offset = offset;
|
||||
ph.MappedAddress = vaddr;
|
||||
ph.PhysicalAddress = vaddr;
|
||||
|
|
@ -130,21 +130,11 @@ std::uint16_t ProgramHeaderLayoutBuilder::WriteLayout(
|
|||
const ProgramHeaderLayoutRequest& request
|
||||
) const {
|
||||
std::uint16_t keptCount = 0;
|
||||
std::uint64_t keptMinVaddr = UINT64_MAX;
|
||||
std::uint64_t keptMinVaddrAlign = kDefaultLoadAlignment;
|
||||
for (const auto& ph : request.OriginalHeaders) {
|
||||
if (_segmentFilter->ShouldSkip(ph))
|
||||
continue;
|
||||
keptCount++;
|
||||
if (ph.Type == PT_LOAD && ph.MappedAddress < keptMinVaddr) {
|
||||
keptMinVaddr = ph.MappedAddress;
|
||||
keptMinVaddrAlign = ph.Alignment;
|
||||
}
|
||||
}
|
||||
if (keptMinVaddr == UINT64_MAX)
|
||||
throw Domain::RelinkerException("No kept PT_LOAD segment to anchor the header block against");
|
||||
if (keptMinVaddrAlign == 0)
|
||||
throw Domain::RelinkerException("Lowest kept PT_LOAD has zero alignment");
|
||||
|
||||
const std::uint16_t neededPh = keptCount + kSyntheticProgramHeaderCount;
|
||||
if (neededPh > request.PhNum)
|
||||
|
|
@ -153,14 +143,9 @@ std::uint16_t ProgramHeaderLayoutBuilder::WriteLayout(
|
|||
", available " + std::to_string(request.PhNum));
|
||||
|
||||
const std::uint64_t headerBlockSize = request.PhOff + static_cast<std::uint64_t>(neededPh) * request.PhEntSize;
|
||||
if (headerBlockSize >= keptMinVaddr)
|
||||
throw Domain::RelinkerException(
|
||||
"Header block does not fit below the lowest kept PT_LOAD: need " +
|
||||
std::to_string(headerBlockSize) + " bytes, only " + std::to_string(keptMinVaddr) + " available");
|
||||
|
||||
const std::uint64_t headerBlockVaddr = (keptMinVaddr - headerBlockSize) & ~(keptMinVaddrAlign - 1);
|
||||
if (headerBlockVaddr + headerBlockSize > keptMinVaddr)
|
||||
throw Domain::RelinkerException("Header block would overlap the lowest kept PT_LOAD after alignment");
|
||||
const std::uint64_t headerBlockAlign = kDefaultLoadAlignment;
|
||||
const std::uint64_t headerBlockVaddr =
|
||||
(request.ExtraBlockVaddr + request.ExtraBlockSize + headerBlockAlign - 1) & ~(headerBlockAlign - 1);
|
||||
|
||||
if (request.DynamicSegmentOffset < request.ExtraBlockOffset)
|
||||
throw Domain::RelinkerException("Dynamic segment offset lies before the extra block");
|
||||
|
|
@ -181,7 +166,7 @@ std::uint16_t ProgramHeaderLayoutBuilder::WriteLayout(
|
|||
writtenPh++;
|
||||
|
||||
const std::size_t headerLoadEntOff = static_cast<std::size_t>(request.PhOff) + writtenPh * request.PhEntSize;
|
||||
_writeProgramHeader(buf, headerLoadEntOff, _makeHeaderBlockLoad(headerBlockVaddr, headerBlockSize, keptMinVaddrAlign));
|
||||
_writeProgramHeader(buf, headerLoadEntOff, _makeHeaderBlockLoad(headerBlockVaddr, headerBlockSize, headerBlockAlign));
|
||||
writtenPh++;
|
||||
|
||||
for (const auto& ph : request.OriginalHeaders) {
|
||||
|
|
|
|||
|
|
@ -10,14 +10,9 @@ bool SegmentFilter::_isSceSpecificSegment(const std::uint32_t type) const {
|
|||
|| (type >= PT_LOOS && type <= PT_HIOS);
|
||||
}
|
||||
|
||||
bool SegmentFilter::_isNullPageLoad(const Domain::ProgramHeader& ph) const {
|
||||
return ph.Type == PT_LOAD && ph.MappedAddress == 0;
|
||||
}
|
||||
|
||||
bool SegmentFilter::ShouldSkip(const Domain::ProgramHeader& ph) const {
|
||||
if (_isSceSpecificSegment(ph.Type)) return true;
|
||||
if (ph.Type == PT_DYNAMIC) return true;
|
||||
if (_isNullPageLoad(ph)) return true;
|
||||
if (ph.Type == PT_NOTE && ph.MappedAddress == 0 && ph.FileSize > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,10 +107,11 @@ std::vector<std::uint8_t> LinuxElfPatcher::Patch(
|
|||
|
||||
const std::uint64_t realEntryVaddr = *reinterpret_cast<const std::uint64_t*>(buf.data() + kEhdrEntryOffset);
|
||||
const auto stubOff = static_cast<std::uint64_t>(buf.size());
|
||||
const auto stubBytes = _entryStubBuilder->BuildEntryStub(stubOff, realEntryVaddr);
|
||||
const auto stubVaddr = vaddrOfExtraBlockOffset(stubOff);
|
||||
const auto stubBytes = _entryStubBuilder->BuildEntryStub(stubVaddr, realEntryVaddr);
|
||||
for (std::uint8_t b : stubBytes)
|
||||
buf.push_back(b);
|
||||
_byteWriter->WriteU64(buf, kEhdrEntryOffset, stubOff);
|
||||
_byteWriter->WriteU64(buf, kEhdrEntryOffset, stubVaddr);
|
||||
|
||||
static constexpr char kInterp[] = "/lib64/ld-linux-x86-64.so.2";
|
||||
const auto interpOff = static_cast<std::uint64_t>(buf.size());
|
||||
|
|
|
|||
Loading…
Reference in New Issue