1919#include < loader/relocations.h>
2020
2121#include < algorithm>
22+ #include < cstdint>
23+ #include < optional>
2224
2325// There are many relocation types, but LLVM only emits a few, only those
2426// present in lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp are implemented
@@ -76,33 +78,58 @@ inline Integer setBitRange(Integer value, Integer subvalue, int first,
7678 return (value & ~mask) | ((subvalue << first) & mask);
7779}
7880
79- bool resolveX86_32 (const loader::Relocation &r, loader::ElfMap &map) {
80- const uint32_t relocation_offset = r.offset & 0xFFFFFFFF ;
81- const int32_t addend = static_cast <int32_t >(r.addend );
81+ // Returns a triple of common variables used in relocation calculation:
82+ // * Writable position in for relocations (host memory)
83+ // * P - position of the relocation (target memory)
84+ // * S - value of the symbol in the symbol table (target memory)
85+ template <typename T>
86+ std::optional<std::tuple<uint8_t *, T, T>> decomposeRelocation (
87+ const loader::Relocation &r, loader::ElfMap &map) {
88+ static_assert (std::is_same_v<T, uint32_t > || std::is_same_v<T, uint64_t >,
89+ " Invalid relocation size" );
90+ using SignedT = std::make_signed_t <T>;
91+ const T relocation_offset = r.offset & 0xFFFFFFFF ;
92+ const SignedT addend = static_cast <SignedT>(r.addend );
8293
83- uint32_t symbol_target_address = static_cast < uint32_t >(
84- map.getSymbolTargetAddress (r.symbol_index ).value_or (0 ));
94+ T symbol_target_address =
95+ static_cast <T>( map.getSymbolTargetAddress (r.symbol_index ).value_or (0 ));
8596 if (symbol_target_address == 0 ) {
8697#ifndef NDEBUG
8798 auto name = map.getSymbolName (r.symbol_index ).value_or (" <unknown symbol>" );
8899 (void )fprintf (stderr, " Missing symbol: %.*s\n " , (int )name.size (),
89100 name.data ());
90101#endif
91- return false ;
102+ return std:: nullopt ;
92103 }
93104 symbol_target_address += addend;
94- const uint32_t relocated_section_base = static_cast < uint32_t >(
95- map.getSectionTargetAddress (r.section_index ).value_or (0 ));
105+ const T relocated_section_base =
106+ static_cast <T>( map.getSectionTargetAddress (r.section_index ).value_or (0 ));
96107 if (relocated_section_base == 0 ) {
97- return false ;
108+ return std:: nullopt ;
98109 }
99110 uint8_t *relocated_section_begin =
100111 map.getSectionWritableAddress (r.section_index ).value_or (nullptr );
101112 if (relocated_section_begin == nullptr ) {
102- return false ;
113+ return std:: nullopt ;
103114 }
115+
104116 uint8_t *relocation_address = relocated_section_begin + relocation_offset;
105117
118+ const T relocation_target_address =
119+ relocated_section_base + relocation_offset;
120+
121+ return std::make_tuple (relocation_address, relocation_target_address,
122+ symbol_target_address);
123+ }
124+
125+ bool resolveX86_32 (const loader::Relocation &r, loader::ElfMap &map) {
126+ auto relocation_data = decomposeRelocation<uint32_t >(r, map);
127+ if (!relocation_data) {
128+ return false ;
129+ }
130+ auto [relocation_address, relocated_target_address, symbol_target_address] =
131+ *relocation_data;
132+
106133 using namespace loader ::RelocationTypes::X86_32;
107134 switch (r.type ) {
108135 default :
@@ -135,15 +162,14 @@ bool resolveX86_32(const loader::Relocation &r, loader::ElfMap &map) {
135162 // R_386_PC32 stores an addend at the relocation target as an int8_t
136163 uint8_t implicit_addend;
137164 cargo::read_little_endian (&implicit_addend, relocation_address);
138- const uint32_t value = symbol_target_address - relocated_section_base -
139- relocation_offset +
165+ const uint32_t value = symbol_target_address - relocated_target_address +
140166 static_cast <int8_t >(implicit_addend);
141167 cargo::write_little_endian (value, relocation_address);
142168 break ;
143169 }
144170 case R_386_PC16: {
145171 const uint32_t real_value =
146- symbol_target_address - relocated_section_base - relocation_offset ;
172+ symbol_target_address - relocated_target_address ;
147173 const uint16_t trunc_value = real_value & 0xFFFF ;
148174 if (static_cast <int32_t >(real_value) !=
149175 static_cast <int16_t >(trunc_value)) {
@@ -154,7 +180,7 @@ bool resolveX86_32(const loader::Relocation &r, loader::ElfMap &map) {
154180 }
155181 case R_386_PC8: {
156182 const uint32_t real_value =
157- symbol_target_address - relocated_section_base - relocation_offset ;
183+ symbol_target_address - relocated_target_address ;
158184 const uint8_t trunc_value = real_value & 0xFF ;
159185 if (static_cast <int32_t >(real_value) !=
160186 static_cast <int8_t >(trunc_value)) {
@@ -168,31 +194,12 @@ bool resolveX86_32(const loader::Relocation &r, loader::ElfMap &map) {
168194}
169195
170196bool resolveX86_64 (const loader::Relocation &r, loader::ElfMap &map) {
171- const uint64_t relocation_offset = r.offset & 0xFFFFFFFF ;
172- const int64_t addend = r.addend ;
173-
174- uint64_t symbol_target_address =
175- map.getSymbolTargetAddress (r.symbol_index ).value_or (0 );
176- if (symbol_target_address == 0 ) {
177- #ifndef NDEBUG
178- auto name = map.getSymbolName (r.symbol_index ).value_or (" <unknown symbol>" );
179- (void )fprintf (stderr, " Missing symbol: %.*s\n " , (int )name.size (),
180- name.data ());
181- #endif
197+ auto relocation_data = decomposeRelocation<uint64_t >(r, map);
198+ if (!relocation_data) {
182199 return false ;
183200 }
184- symbol_target_address += addend;
185- const uint64_t relocated_section_base =
186- map.getSectionTargetAddress (r.section_index ).value_or (0 );
187- if (relocated_section_base == 0 ) {
188- return false ;
189- }
190- uint8_t *relocated_section_begin =
191- map.getSectionWritableAddress (r.section_index ).value_or (nullptr );
192- if (relocated_section_begin == nullptr ) {
193- return false ;
194- }
195- uint8_t *relocation_address = relocated_section_begin + relocation_offset;
201+ auto [relocation_address, relocated_target_address, symbol_target_address] =
202+ *relocation_data;
196203
197204 using namespace loader ::RelocationTypes::X86_64;
198205 switch (r.type ) {
@@ -210,8 +217,7 @@ bool resolveX86_64(const loader::Relocation &r, loader::ElfMap &map) {
210217 }
211218 // PC-relative 64-bit relocation
212219 case R_X86_64_PC64: {
213- const uint64_t value =
214- symbol_target_address - relocated_section_base - relocation_offset;
220+ const uint64_t value = symbol_target_address - relocated_target_address;
215221 cargo::write_little_endian (value, relocation_address);
216222 break ;
217223 }
@@ -240,7 +246,7 @@ bool resolveX86_64(const loader::Relocation &r, loader::ElfMap &map) {
240246 // sign-extensions are valid
241247 case R_X86_64_PC32: {
242248 const uint64_t real_value =
243- symbol_target_address - relocated_section_base - relocation_offset ;
249+ symbol_target_address - relocated_target_address ;
244250 const uint32_t trunc_value = real_value & 0xFFFFFFFF ;
245251 if (static_cast <int64_t >(real_value) !=
246252 static_cast <int32_t >(trunc_value)) {
@@ -251,7 +257,7 @@ bool resolveX86_64(const loader::Relocation &r, loader::ElfMap &map) {
251257 }
252258 case R_X86_64_PC16: {
253259 const uint64_t real_value =
254- symbol_target_address - relocated_section_base - relocation_offset ;
260+ symbol_target_address - relocated_target_address ;
255261 const uint16_t trunc_value = real_value & 0xFFFF ;
256262 if (static_cast <int64_t >(real_value) !=
257263 static_cast <int16_t >(trunc_value)) {
@@ -262,7 +268,7 @@ bool resolveX86_64(const loader::Relocation &r, loader::ElfMap &map) {
262268 }
263269 case R_X86_64_PC8: {
264270 const uint64_t real_value =
265- symbol_target_address - relocated_section_base - relocation_offset ;
271+ symbol_target_address - relocated_target_address ;
266272 const uint8_t trunc_value = real_value & 0xFF ;
267273 if (static_cast <int64_t >(real_value) !=
268274 static_cast <int8_t >(trunc_value)) {
@@ -278,33 +284,16 @@ bool resolveX86_64(const loader::Relocation &r, loader::ElfMap &map) {
278284// assumes little-endian Arm, because big-endian is extremely rare
279285bool resolveArm (const loader::Relocation &r, loader::ElfMap &map,
280286 loader::Relocation::StubMap &stubs) {
281- const uint32_t relocation_offset = r.offset & 0xFFFFFFFF ;
282- const int32_t addend = static_cast <int32_t >(r.addend );
283-
284- uint32_t symbol_target_address = static_cast <uint32_t >(
285- map.getSymbolTargetAddress (r.symbol_index ).value_or (0 ));
286- if (symbol_target_address == 0 ) {
287- #ifndef NDEBUG
288- auto name = map.getSymbolName (r.symbol_index ).value_or (" <unknown symbol>" );
289- (void )fprintf (stderr, " Missing symbol: %.*s\n " , (int )name.size (),
290- name.data ());
291- #endif
287+ auto relocation_data = decomposeRelocation<uint32_t >(r, map);
288+ if (!relocation_data) {
292289 return false ;
293290 }
294- symbol_target_address += addend;
295- const uint32_t relocated_section_base = static_cast <uint32_t >(
296- map.getSectionTargetAddress (r.section_index ).value_or (0 ));
297- if (relocated_section_base == 0 ) {
298- return false ;
299- }
300- uint8_t *relocated_section_begin =
301- map.getSectionWritableAddress (r.section_index ).value_or (nullptr );
302- if (relocated_section_begin == nullptr ) {
303- return false ;
304- }
305- uint8_t *relocation_address = relocated_section_begin + relocation_offset;
306- const uint32_t relocation_target_address =
307- relocated_section_base + relocation_offset;
291+ auto [relocation_address, relocation_target_address, symbol_tgt_address] =
292+ *relocation_data;
293+ // We can't auto-capture structured bindings (lambda, below) so make an
294+ // explicit copy of it here.
295+ auto symbol_target_address = symbol_tgt_address;
296+
308297 uint32_t value;
309298 cargo::read_little_endian (&value, relocation_address);
310299
@@ -394,38 +383,18 @@ bool resolveAArch64(const loader::Relocation &r, loader::ElfMap &map,
394383 map.getSymbolName (r.symbol_index ).value_or (" <unknown symbol>" );
395384#endif
396385
397- const uint64_t relocation_offset = r.offset ;
398- const int64_t addend = r.addend ;
399-
400- uint64_t symbol_target_address =
401- map.getSymbolTargetAddress (r.symbol_index ).value_or (0 );
402- if (symbol_target_address == 0 ) {
403- #ifndef NDEBUG
404- (void )fprintf (stderr, " Missing symbol: %.*s\n " , (int )symbol_name.size (),
405- symbol_name.data ());
406- #endif
407- return false ;
408- }
409- symbol_target_address += addend;
410- const uint64_t relocated_section_base =
411- map.getSectionTargetAddress (r.section_index ).value_or (0 );
412- if (relocated_section_base == 0 ) {
413- return false ;
414- }
415- uint8_t *relocated_section_begin =
416- map.getSectionWritableAddress (r.section_index ).value_or (nullptr );
417- if (relocated_section_begin == nullptr ) {
386+ auto relocation_data = decomposeRelocation<uint64_t >(r, map);
387+ if (!relocation_data) {
418388 return false ;
419389 }
420- uint8_t * relocation_address = relocated_section_begin + relocation_offset;
421- const uint64_t relocation_target_address =
422- relocated_section_base + relocation_offset;
390+ auto [ relocation_address, relocation_target_address, symbol_target_address] =
391+ *relocation_data;
392+
423393 uint64_t value;
424394 cargo::read_little_endian (&value, relocation_address);
425395 uint32_t value32;
426396 cargo::read_little_endian (&value32, relocation_address);
427397
428- using namespace loader ::RelocationTypes::AArch64;
429398 // returns the address of the stub to jump to
430399 auto getOrCreateStub = [&](uint64_t symbol_target_address) -> uint64_t {
431400 auto found_stub_target = stubs.getTarget (symbol_target_address);
@@ -472,6 +441,7 @@ bool resolveAArch64(const loader::Relocation &r, loader::ElfMap &map,
472441 return target + 4 ;
473442 };
474443
444+ using namespace loader ::RelocationTypes::AArch64;
475445 switch (r.type ) {
476446 default :
477447 CARGO_ASSERT (0 , " Unsupported relocation type." );
0 commit comments