mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 14:31:24 +12:00
Optimize memory usage of ELF loader
Do not duplicate shdr memory when it is present in phdr.
This commit is contained in:
parent
bb92154145
commit
744a1528cc
3 changed files with 74 additions and 6 deletions
|
@ -2783,7 +2783,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
|
||||||
_sec.addr = addr;
|
_sec.addr = addr;
|
||||||
relm.secs.emplace_back(_sec);
|
relm.secs.emplace_back(_sec);
|
||||||
|
|
||||||
std::memcpy(vm::base(addr), s.bin.data(), size);
|
std::memcpy(vm::base(addr), s.get_bin().data(), size);
|
||||||
addr = utils::align<u32>(addr + size, 128);
|
addr = utils::align<u32>(addr + size, 128);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -410,7 +410,7 @@ void spu_load_rel_exec(const spu_rel_object& elf)
|
||||||
{
|
{
|
||||||
if (shdr.sh_type == sec_type::sht_progbits && shdr.sh_flags().all_of(sh_flag::shf_alloc))
|
if (shdr.sh_type == sec_type::sht_progbits && shdr.sh_flags().all_of(sh_flag::shf_alloc))
|
||||||
{
|
{
|
||||||
std::memcpy(spu->_ptr<void>(offs), shdr.bin.data(), shdr.sh_size);
|
std::memcpy(spu->_ptr<void>(offs), shdr.get_bin().data(), shdr.sh_size);
|
||||||
offs = utils::align<u32>(offs + shdr.sh_size, 4);
|
offs = utils::align<u32>(offs + shdr.sh_size, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "../../Utilities/File.h"
|
#include "../../Utilities/File.h"
|
||||||
#include "../../Utilities/bit_set.h"
|
#include "../../Utilities/bit_set.h"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
enum class elf_os : u8
|
enum class elf_os : u8
|
||||||
{
|
{
|
||||||
none = 0,
|
none = 0,
|
||||||
|
@ -191,10 +193,21 @@ template<template<typename T> class en_t, typename sz_t>
|
||||||
struct elf_shdata final : elf_shdr<en_t, sz_t>
|
struct elf_shdata final : elf_shdr<en_t, sz_t>
|
||||||
{
|
{
|
||||||
std::vector<uchar> bin{};
|
std::vector<uchar> bin{};
|
||||||
|
std::span<const uchar> bin_view{};
|
||||||
|
|
||||||
using base = elf_shdr<en_t, sz_t>;
|
using base = elf_shdr<en_t, sz_t>;
|
||||||
|
|
||||||
elf_shdata() = default;
|
elf_shdata() = default;
|
||||||
|
|
||||||
|
std::span<const uchar> get_bin() const
|
||||||
|
{
|
||||||
|
if (!bin_view.empty())
|
||||||
|
{
|
||||||
|
return bin_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {bin.data(), bin.size()};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ELF loading options
|
// ELF loading options
|
||||||
|
@ -340,6 +353,26 @@ public:
|
||||||
|
|
||||||
if (!(opts & elf_opt::no_data) && is_memorizable_section(shdr.sh_type, shdr.sh_flags()))
|
if (!(opts & elf_opt::no_data) && is_memorizable_section(shdr.sh_type, shdr.sh_flags()))
|
||||||
{
|
{
|
||||||
|
usz p_index = umax;
|
||||||
|
|
||||||
|
for (const auto& hdr : _phdrs)
|
||||||
|
{
|
||||||
|
// Try to find it in phdr data instead of allocating new section
|
||||||
|
p_index++;
|
||||||
|
|
||||||
|
if (hdr.p_offset <= shdr.sh_offset && shdr.sh_offset + shdr.sh_size - 1 <= hdr.p_offset + hdr.p_filesz - 1)
|
||||||
|
{
|
||||||
|
const auto& prog = ::at32(progs, p_index);
|
||||||
|
shdrs.back().bin_view = {prog.bin.data() + shdr.sh_offset - hdr.p_offset, shdr.sh_size};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shdrs.back().bin_view.empty())
|
||||||
|
{
|
||||||
|
// Optimized
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
stream.seek(offset + shdr.sh_offset);
|
stream.seek(offset + shdr.sh_offset);
|
||||||
if (!stream.read(shdrs.back().bin, shdr.sh_size))
|
if (!stream.read(shdrs.back().bin, shdr.sh_size))
|
||||||
return set_error(elf_error::stream_data);
|
return set_error(elf_error::stream_data);
|
||||||
|
@ -400,14 +433,49 @@ public:
|
||||||
stream.write(shdr_t{});
|
stream.write(shdr_t{});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (shdr_t shdr : shdrs)
|
for (const auto& shdr : shdrs)
|
||||||
{
|
{
|
||||||
|
shdr_t out = static_cast<shdr_t>(shdr);
|
||||||
|
|
||||||
if (is_memorizable_section(shdr.sh_type, shdr.sh_flags()))
|
if (is_memorizable_section(shdr.sh_type, shdr.sh_flags()))
|
||||||
{
|
{
|
||||||
shdr.sh_offset = std::exchange(off, off + shdr.sh_size);
|
usz p_index = umax;
|
||||||
|
usz data_base = header.e_shoff + u32{sizeof(shdr_t)} * ::size32(shdrs);
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
for (const auto& hdr : progs)
|
||||||
|
{
|
||||||
|
if (shdr.bin_view.empty())
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.write(shdr);
|
// Try to find it in phdr data instead of writing new section
|
||||||
|
p_index++;
|
||||||
|
|
||||||
|
// Rely on previous sh_offset value!
|
||||||
|
if (hdr.p_offset <= shdr.sh_offset && shdr.sh_offset + shdr.sh_size - 1 <= hdr.p_offset + hdr.p_filesz - 1)
|
||||||
|
{
|
||||||
|
const auto& prog = ::at32(progs, p_index);
|
||||||
|
out.sh_offset = data_base + shdr.sh_offset - hdr.p_offset;
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_base += ::at32(progs, p_index).p_filesz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
// Optimized
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.sh_offset = std::exchange(off, off + shdr.sh_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.write(static_cast<shdr_t>(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write data
|
// Write data
|
||||||
|
@ -418,7 +486,7 @@ public:
|
||||||
|
|
||||||
for (const auto& shdr : shdrs)
|
for (const auto& shdr : shdrs)
|
||||||
{
|
{
|
||||||
if (!is_memorizable_section(shdr.sh_type, shdr.sh_flags()))
|
if (!is_memorizable_section(shdr.sh_type, shdr.sh_flags()) || !shdr.bin_view.empty())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue