Repository navigation
Expand file tree
/
Copy pathMacOsMachOPatcher.cpp
More file actions
82 lines (73 loc) · 4.15 KB
/
Copy pathMacOsMachOPatcher.cpp
File metadata and controls
82 lines (73 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <elfpatcher/macos/MacOsMachOPatcher.hpp>
#include <elfpatcher/macos/MacOsImage.hpp>
#include <elfpatcher/windows/WindowsLoadImage.hpp>
#include <elfpatcher/windows/WindowsRelocationBuilder.hpp>
#include <io/BufferUtils.hpp>
#include <algorithm>
#include <set>
#include <string>
namespace Elfpatcher::MacOs {
std::string MachOLoadPath(const std::string& path, const std::string& origin) {
if (path == "$ORIGIN") return origin;
if (path.starts_with("$ORIGIN/")) return origin + path.substr(7);
return path;
}
std::vector<std::string> MachORunPaths(const std::string& paths, const std::string& origin) {
std::vector<std::string> result;
for (std::size_t begin = 0;;) {
const auto end = paths.find(':', begin);
const auto path = paths.substr(begin, end == std::string::npos ? end : end - begin);
if (path.empty()) throw Domain::RelinkerException("Empty macOS run path component is not supported");
result.push_back(MachOLoadPath(path, origin));
if (end == std::string::npos) break;
begin = end + 1;
}
return result;
}
std::vector<std::string> ReadNeededLibraries(const Domain::SysVDynamicSection& dynamicSection) {
const auto& bytes = dynamicSection.DynamicSegmentData;
if (bytes.size() % 16 != 0) throw Domain::RelinkerException("Invalid dynamic segment size");
std::vector<std::string> result;
std::set<std::string> unique;
for (std::size_t offset = 0; offset < bytes.size(); offset += 16) {
if (Io::ReadU64(bytes, offset) != 1) throw Domain::RelinkerException("Unexpected tag in rebuilt ELF dependency table", offset);
const auto nameOffset = Io::ReadU64(bytes, offset + 8);
if (nameOffset >= dynamicSection.DynStrData.size()) throw Domain::RelinkerException("DT_NEEDED string offset is out of bounds", nameOffset);
auto name = Windows::ReadString(dynamicSection.DynStrData, static_cast<std::size_t>(nameOffset));
if (name.empty()) throw Domain::RelinkerException("Invalid DT_NEEDED library: " + name);
if (unique.insert(name).second) result.push_back(std::move(name));
}
if (unique.contains("libSceLibcInternal.prx") && !unique.contains("libc.prx")) result.push_back("libc.prx");
return result;
}
std::string MachODependency(const std::string& name, const std::string& origin) {
if (name.starts_with("$ORIGIN")) return MachOLoadPath(name, origin);
if (name.find('/') != std::string::npos) throw Domain::RelinkerException("Unsupported dependency path: " + name);
return "@rpath/" + name;
}
std::vector<std::uint8_t> MacOsMachOPatcher::Patch(std::vector<std::uint8_t> sourceElf, const std::vector<Domain::ProgramHeader>& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, const std::uint64_t originalPltGotVaddr, const std::string& runPath, const bool lazyBinding, const bool dependencyDiagnostics, const std::vector<Codegen::TrampolineSite>& trampolines) {
if (dependencyDiagnostics)
throw Domain::RelinkerException("macOS target does not support --windows-diagnostics");
static_cast<void>(lazyBinding);
Windows::WindowsLoadImage image(sourceElf, originalHeaders);
if (originalPltGotVaddr != 0)
image.GetRva(originalPltGotVaddr, 8);
const auto relocations = Windows::WindowsRelocationBuilder().Apply(image, dynamicSection, originalHeaders);
MacOsImageInput input;
input.Executable = true;
input.Source = &sourceElf;
input.Headers = &originalHeaders;
input.Image = ℑ
input.Rebases = relocations.BaseRelocations;
for (const auto& import : relocations.Imports)
input.Binds.push_back({"_" + import.Name, import.TargetRva, static_cast<std::int64_t>(import.Addend), import.Weak});
for (const auto& library : ReadNeededLibraries(dynamicSection))
input.Dylibs.push_back(MachODependency(library, "@executable_path"));
if (std::find(input.Dylibs.begin(), input.Dylibs.end(), "@rpath/libkernel.prx") == input.Dylibs.end())
input.Dylibs.push_back("@rpath/libkernel.prx");
input.RunPaths = MachORunPaths(runPath, "@executable_path");
input.EntryRva = image.GetEntryRva();
input.Trampolines = &trampolines;
return WriteMacOsImage(input);
}
}