mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
Let an explicit function map override the JAL-target scan
On an ELF with no symbols and no DWARF, parse() carves functions from JAL
targets. Those carvings end at the next JAL target or, for the last one in a
region, at the end of the code section, so on a single-PROGBITS executable
they can run straight through interleaved rodata.
loadGhidraFunctionMap() appended its rows to the same vector and then purged
auto-named entries only where no map row shared the start address. Since both
the carvings ("sub_") and the names Ghidra exports by default ("FUN_") count
as auto-generated, a carving that shared a start with a map row survived the
purge and then won the "larger end" tie-break, so the imprecise bounds
replaced the ones the map had just supplied.
Collect the map rows into a local vector, drop every auto-named carving once
the map has parsed, and append the rows afterwards. Entries named from
symbols or DWARF are unaffected.
On a 3 MB Metrowerks-built PS2 executable with an 11,491-row map, 5,613
functions (48.8%) had been emitted with inflated bounds; the worst grew from
368 bytes to 0x51 KB and produced 22 MB of C++ decoding string data as
instructions. Output for that function is now 19 KB and total output drops
from 235 MB to 180 MB.
This commit is contained in:
@@ -986,6 +986,7 @@ namespace ps2recomp
|
||||
int skippedNonExecutable = 0;
|
||||
int skippedInvalidRange = 0;
|
||||
std::unordered_set<uint32_t> mapStarts;
|
||||
std::vector<Function> mapFunctions;
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.empty())
|
||||
@@ -1029,7 +1030,7 @@ namespace ps2recomp
|
||||
func.isStub = false;
|
||||
func.isSkipped = false;
|
||||
|
||||
m_extraFunctions.push_back(std::move(func));
|
||||
mapFunctions.push_back(std::move(func));
|
||||
mapStarts.insert(start);
|
||||
count++;
|
||||
}
|
||||
@@ -1062,14 +1063,27 @@ namespace ps2recomp
|
||||
}
|
||||
}
|
||||
|
||||
// An explicit function map is authoritative over the internal JAL-target
|
||||
// scan. Those carvings end at the next JAL target or, for the last one in
|
||||
// a region, at the end of the code section - which on single-PROGBITS
|
||||
// executables runs straight through interleaved rodata. Because both the
|
||||
// carvings ("sub_") and typical map names ("FUN_") count as
|
||||
// auto-generated, a carving sharing a start with a map row used to
|
||||
// survive this purge and then win the "larger end" tie-break below,
|
||||
// replacing precise bounds with runaway ones. Drop every auto-named
|
||||
// carving instead, then append the map rows.
|
||||
m_extraFunctions.erase(
|
||||
std::remove_if(m_extraFunctions.begin(), m_extraFunctions.end(),
|
||||
[&](const Function &func)
|
||||
{
|
||||
return IsAutoGeneratedName(func.name) && !mapStarts.contains(func.start);
|
||||
return IsAutoGeneratedName(func.name);
|
||||
}),
|
||||
m_extraFunctions.end());
|
||||
|
||||
m_extraFunctions.insert(m_extraFunctions.end(),
|
||||
std::make_move_iterator(mapFunctions.begin()),
|
||||
std::make_move_iterator(mapFunctions.end()));
|
||||
|
||||
std::sort(m_extraFunctions.begin(), m_extraFunctions.end(),
|
||||
[](const Function &a, const Function &b)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user