Skip to content

Commit 5bd0a05

Browse files
committed
[ResGen] weak symbol support
1 parent 2343418 commit 5bd0a05

File tree

12 files changed

+103
-55
lines changed

12 files changed

+103
-55
lines changed

ResGen/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ Resolver generator.
44

55
## Usage
66

7-
> ResGen [options] [inputs...] -o [output]
7+
> ResGen [options] [inputs...] -o|--out [output]
88
99
Options:
10-
- `--rules`: JSON file(s) containing symbol definitions
11-
- `--name`: Set the symbol name for the resolver (default: `ctrdlProgramResolver`)
10+
- `-r|--rules`: JSON file(s) containing symbol definitions
11+
- `-n|--name`: Set the symbol name for the resolver (default: `ctrdlProgramResolver`)
1212

1313
### Symbol definition files (SymDefs)
1414

@@ -19,6 +19,7 @@ SymDefs specify rules for certain symbols.
1919
// Match symbols by regex pattern
2020
"{PATTERN}" : {
2121
"name" : "{NEW NAME}", // Replace the symbol name (default: null (retain name))
22+
"weak" : true | false, // Define as weak (default: false)
2223
"exclude" : true | false, // Exclude this symbol (default: false)
2324
"partial_match" : true | false // Match name partially (default: false)
2425
}

ResGen/Source/Binary.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,20 @@ static bool parse(const std::string& fileName, std::ifstream& f, SymList& out) {
192192
}
193193

194194
// Read symbols.
195+
const auto& isWeak = [](unsigned char info) {
196+
if constexpr (std::is_same_v<HeaderType, Elf64_Ehdr>) {
197+
return ELF64_ST_BIND(info) == STB_WEAK;
198+
} else {
199+
return ELF32_ST_BIND(info) == STB_WEAK;
200+
}
201+
};
202+
195203
for (auto& sym : symEntries) {
196204
if (sym.st_name == STN_UNDEF || sym.st_shndx != SHN_UNDEF)
197205
continue;
198206

199207
const char* name = &stringTable[sym.st_name];
200-
out.insert(name);
208+
out.insert({name, isWeak(sym.st_info) });
201209
}
202210

203211
return true;

ResGen/Source/CmdArgs.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ CmdArgs::CmdArgs() : m_Options("ResGen", "Resolver Generator") {
99
m_Options.add_options()
1010
("h,help", "Show help")
1111
("inputs", "", cxxopts::value<std::vector<std::string>>())
12-
("o,output", "Output file", cxxopts::value<std::string>())
13-
("rules", "JSON file(s) containing symbol definitions", cxxopts::value<std::vector<std::string>>())
14-
("name", "Set the symbol name for the resolver", cxxopts::value<std::string>()->default_value(DEFAULT_RESOLVER_NAME));
12+
("o,out", "Output file", cxxopts::value<std::string>())
13+
("r,rules", "JSON file(s) containing symbol definitions", cxxopts::value<std::vector<std::string>>())
14+
("n,name", "Set the symbol name for the resolver", cxxopts::value<std::string>()->default_value(DEFAULT_RESOLVER_NAME));
1515

1616
m_Options.parse_positional({ "inputs" });
1717
}
1818

1919
bool CmdArgs::parse(int argc, const char* const* argv) {
2020
m_Inputs.clear();
21-
m_DefinitionLists.clear();
21+
m_Rules.clear();
2222
m_ResolverName.clear();
2323

2424
auto result = m_Options.parse(argc, argv);
@@ -33,12 +33,12 @@ bool CmdArgs::parse(int argc, const char* const* argv) {
3333
m_Inputs.insert(entry);
3434
}
3535

36-
if (result["output"].count())
37-
m_Output = result["output"].as<std::string>();
36+
if (result["out"].count())
37+
m_Output = result["out"].as<std::string>();
3838

3939
if (result["rules"].count()) {
4040
for (const auto& entry : result["rules"].as<std::vector<std::string>>())
41-
m_DefinitionLists.insert(entry);
41+
m_Rules.insert(entry);
4242
}
4343

4444
m_ResolverName = result["name"].as<std::string>();

ResGen/Source/CmdArgs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CmdArgs {
1313
cxxopts::Options m_Options;
1414
std::unordered_set<std::filesystem::path> m_Inputs;
1515
std::filesystem::path m_Output;
16-
std::unordered_set<std::filesystem::path> m_DefinitionLists;
16+
std::unordered_set<std::filesystem::path> m_Rules;
1717
std::string m_ResolverName;
1818

1919
public:
@@ -23,7 +23,7 @@ class CmdArgs {
2323

2424
const std::unordered_set<std::filesystem::path>& inputs() const { return m_Inputs; }
2525
const std::filesystem::path& output() const { return m_Output; }
26-
const std::unordered_set<std::filesystem::path>& definitionLists() const { return m_DefinitionLists; }
26+
const std::unordered_set<std::filesystem::path>& rules() const { return m_Rules; }
2727
const std::string& resolverName() const { return m_ResolverName; }
2828
};
2929

ResGen/Source/Main.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,28 @@ int main(int argc, const char* const* argv) {
3333
return 1;
3434
}
3535

36-
// Parse symdefs.
36+
// Parse rules.
3737
SymDefs defs;
38-
for (const auto& defFile : args.definitionLists()) {
39-
if (!defs.parse(defFile))
38+
for (const auto& ruleFile : args.rules()) {
39+
if (!defs.parseFile(ruleFile))
4040
return 1;
4141
}
4242

4343
// Generate symbol map.
4444
SymMap symMap;
4545

4646
for (const auto& sym : syms) {
47-
if (auto name = defs.resolve(sym))
48-
symMap[sym] = *name;
47+
const auto rule = defs.ruleForName(sym.name);
48+
49+
// Leave the original name if no rule matched.
50+
if (!rule) {
51+
symMap[sym.name] = sym;
52+
continue;
53+
} else {
54+
// Apply the name given by the rule, if any.
55+
if (auto name = rule->nameForSymbol(sym.name))
56+
symMap[sym.name] = SymEntry { *name, rule->isWeak() };
57+
}
4958
}
5059

5160
// Generate resolver.

ResGen/Source/ResGenerator.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,13 @@ bool ResGenerator::writeToFile(const std::filesystem::path& path) {
9999

100100
for (const auto& bucket : m_SymTable.buckets()) {
101101
for (const auto& entry : bucket) {
102+
const auto& mapped = m_SymTable.mapped(entry);
103+
104+
if (mapped.isWeak)
105+
f << ".weak " << mapped.name << '\n';
106+
102107
f << ".word " << entry << '\n';
103-
f << ".word " << m_SymTable.mapped(entry) << '\n';
108+
f << ".word " << mapped.name << '\n';
104109
}
105110

106111
f << ".word 0\n";

ResGen/Source/SymTable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static std::uint32_t nearestPowerOf2(std::uint32_t n) {
3434
return 0;
3535
}
3636

37-
size_t SymTable::insertSymbol(const std::string& sym, const std::string& mapped) {
37+
size_t SymTable::insertSymbol(const std::string& sym, const SymEntry& mapped) {
3838
const auto strOff = m_StringTable.size();
3939
m_StringTable.resize(strOff + sym.size() + 1, '\0');
4040
memcpy(m_StringTable.data() + strOff, sym.data(), sym.size());

ResGen/Source/SymTable.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ namespace resgen {
1212
class SymTable {
1313
std::vector<std::uint8_t> m_StringTable;
1414
std::vector<std::vector<size_t>> m_Buckets;
15-
std::unordered_map<size_t, std::string> m_Mapped;
15+
std::unordered_map<size_t, SymEntry> m_Mapped;
1616

17-
size_t insertSymbol(const std::string& sym, const std::string& mapped);
17+
size_t insertSymbol(const std::string& sym, const SymEntry& mapped);
1818
void genHashTable(SymMap&& symbols, std::unordered_map<std::string, size_t>&& offsets);
1919

2020
public:
2121
SymTable(SymMap&& symbols);
2222

2323
const std::vector<std::uint8_t>& stringTable() const { return m_StringTable; }
2424
const std::vector<std::vector<size_t>>& buckets() const { return m_Buckets; }
25-
const std::string& mapped(size_t idx) const { return m_Mapped.at(idx); }
25+
const SymEntry& mapped(size_t idx) const { return m_Mapped.at(idx); }
2626
};
2727

2828
} // namespace resgen

ResGen/Source/Symbol.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,12 @@ bool SymRule::match(std::string_view s) const {
1414
return RE2::FullMatch(s, *m_RE);
1515
}
1616

17-
bool SymDefs::parse(const std::filesystem::path& path) {
18-
const auto fileName = path.filename().string();
17+
bool SymDefs::parseObject(std::string_view fileName, std::string_view content) {
1918
std::unordered_set<std::string> ruleNames;
2019
std::vector<SymRule> rules;
2120

22-
// Read json.
23-
std::ifstream f(path);
24-
if (!f.is_open()) {
25-
resgen::printError(PrintFileInfo {
26-
.fileName = fileName,
27-
.boldText = true,
28-
}, "could not open file");
29-
return false;
30-
}
31-
32-
const auto jsonData = nlohmann::json::parse(f, nullptr, false);
21+
// Parse json.
22+
const auto jsonData = nlohmann::json::parse(content, nullptr, false);
3323
if (!jsonData.is_object()) {
3424
resgen::printError( PrintFileInfo {
3525
.fileName = fileName,
@@ -79,6 +69,19 @@ bool SymDefs::parse(const std::filesystem::path& path) {
7969
name = value["name"].get<std::string>();
8070
}
8171

72+
if (value.contains("weak")) {
73+
if (!value["weak"].is_boolean()) {
74+
resgen::printError( PrintFileInfo {
75+
.fileName = fileName,
76+
.boldText = true,
77+
}, "expected bool for \"weak\" of rule \"{}\"", rule);
78+
return false;
79+
}
80+
81+
if (value["weak"].get<bool>())
82+
flags |= SymRule::FLAG_WEAK;
83+
}
84+
8285
if (value.contains("exclude")) {
8386
if (!value["exclude"].is_boolean()) {
8487
resgen::printError( PrintFileInfo {
@@ -125,6 +128,22 @@ bool SymDefs::parse(const std::filesystem::path& path) {
125128
return true;
126129
}
127130

131+
bool SymDefs::parseFile(const std::filesystem::path& path) {
132+
const auto fileName = path.filename().string();
133+
134+
std::ifstream f(path);
135+
if (!f.is_open()) {
136+
resgen::printError(PrintFileInfo {
137+
.fileName = fileName,
138+
.boldText = true,
139+
}, "could not open file");
140+
return false;
141+
}
142+
143+
const std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
144+
return parseObject(fileName, content);
145+
}
146+
128147
static std::size_t checkSym(std::string_view s) {
129148
for (auto i = 0u; i < s.size(); ++i) {
130149
if (s[i] <= '\x20' || s[i] >= '\x7F')
@@ -170,7 +189,7 @@ static bool parseList(const std::filesystem::path& path, SymList& out) {
170189

171190
// Check for duplicates.
172191
auto tmpIt = syms.find(tmp);
173-
auto otherIt = out.find(tmp);
192+
auto otherIt = out.find(SymEntry{ tmp, false });
174193

175194
if ((tmpIt != syms.end()) || (otherIt != out.end())) {
176195
resgen::printWarning(PrintFileInfo {
@@ -193,7 +212,7 @@ static bool parseList(const std::filesystem::path& path, SymList& out) {
193212
auto it = syms.begin();
194213
while (it != syms.end()) {
195214
auto node = syms.extract(it);
196-
out.insert(node.key());
215+
out.insert({ node.key(), false });
197216
it = syms.begin();
198217
}
199218

ResGen/Source/Symbol.h

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,19 @@
1717

1818
namespace resgen {
1919

20-
using SymList = std::unordered_set<std::string>;
21-
using SymMap = std::unordered_map<std::string, std::string>;
20+
struct SymEntry {
21+
struct Hash {
22+
std::size_t operator()(const SymEntry& other) const noexcept { return std::hash<std::string>{}(other.name); }
23+
};
24+
25+
std::string name;
26+
bool isWeak = false;
27+
28+
bool operator==(const SymEntry& other) const noexcept { return name == other.name; }
29+
};
30+
31+
using SymList = std::unordered_set<SymEntry, SymEntry::Hash>;
32+
using SymMap = std::unordered_map<std::string, SymEntry>;
2233

2334
class InvalidRuleException final : public std::runtime_error {
2435
public:
@@ -27,8 +38,9 @@ class InvalidRuleException final : public std::runtime_error {
2738

2839
class SymRule final {
2940
public:
30-
constexpr static std::size_t FLAG_EXCLUDE = 0x01;
31-
constexpr static std::size_t FLAG_PARTIAL_MATCH = 0x02;
41+
constexpr static std::size_t FLAG_WEAK = 0x01;
42+
constexpr static std::size_t FLAG_EXCLUDE = 0x02;
43+
constexpr static std::size_t FLAG_PARTIAL_MATCH = 0x04;
3244

3345
private:
3446
std::unique_ptr<RE2> m_RE;
@@ -56,6 +68,8 @@ class SymRule final {
5668

5769
return std::string(sym);
5870
}
71+
72+
bool isWeak() const { return m_Flags & FLAG_WEAK; }
5973
};
6074

6175
class SymDefs final {
@@ -65,15 +79,16 @@ class SymDefs final {
6579
public:
6680
SymDefs() {}
6781

68-
bool parse(const std::filesystem::path& path);
82+
bool parseObject(std::string_view fileName, std::string_view content);
83+
bool parseFile(const std::filesystem::path& path);
6984

7085
void clear() {
7186
m_RuleNames.clear();
7287
m_Rules.clear();
7388
}
7489

75-
std::optional<std::string> resolve(std::string_view sym) const {
76-
// Find a rule for this symbol.
90+
// Find a rule for this symbol.
91+
const SymRule* ruleForName(std::string_view sym) const {
7792
const SymRule* matched = nullptr;
7893
std::vector<const SymRule*> otherMatches;
7994
for (const auto& rule : m_Rules) {
@@ -95,8 +110,7 @@ class SymDefs final {
95110
resgen::printNote("matches \"{}\"", rule->pattern());
96111
}
97112

98-
// Return the same name if no rule matched.
99-
return matched ? matched->nameForSymbol(sym) : std::string(sym);
113+
return matched;
100114
}
101115
};
102116

0 commit comments

Comments
 (0)