@@ -206,31 +206,53 @@ static InputSection *findContainingSubsection(SubsectionMap &map,
206
206
void ObjFile::parseRelocations (const section_64 &sec,
207
207
SubsectionMap &subsecMap) {
208
208
auto *buf = reinterpret_cast <const uint8_t *>(mb.getBufferStart ());
209
- ArrayRef<any_relocation_info> anyRelInfos (
210
- reinterpret_cast <const any_relocation_info *>(buf + sec.reloff ),
211
- sec.nreloc );
212
-
213
- for (const any_relocation_info &anyRelInfo : anyRelInfos) {
214
- if (anyRelInfo.r_word0 & R_SCATTERED)
209
+ ArrayRef<relocation_info> relInfos (
210
+ reinterpret_cast <const relocation_info *>(buf + sec.reloff ), sec.nreloc );
211
+
212
+ for (size_t i = 0 ; i < relInfos.size (); i++) {
213
+ // Paired relocations serve as Mach-O's method for attaching a
214
+ // supplemental datum to a primary relocation record. ELF does not
215
+ // need them because the *_RELOC_RELA records contain the extra
216
+ // addend field, vs. *_RELOC_REL which omit the addend.
217
+ //
218
+ // The {X86_64,ARM64}_RELOC_SUBTRACTOR record holds the subtrahend,
219
+ // and the paired *_RELOC_UNSIGNED record holds the minuend. The
220
+ // datum for each is a symbolic address. The result is the runtime
221
+ // offset between two addresses.
222
+ //
223
+ // The ARM64_RELOC_ADDEND record holds the addend, and the paired
224
+ // ARM64_RELOC_BRANCH26 or ARM64_RELOC_PAGE21/PAGEOFF12 holds the
225
+ // base symbolic address.
226
+ //
227
+ // Note: X86 does not use *_RELOC_ADDEND because it can embed an
228
+ // addend into the instruction stream. On X86, a relocatable address
229
+ // field always occupies an entire contiguous sequence of byte(s),
230
+ // so there is no need to merge opcode bits with address
231
+ // bits. Therefore, it's easy and convenient to store addends in the
232
+ // instruction-stream bytes that would otherwise contain zeroes. By
233
+ // contrast, RISC ISAs such as ARM64 mix opcode bits with with
234
+ // address bits so that bitwise arithmetic is necessary to extract
235
+ // and insert them. Storing addends in the instruction stream is
236
+ // possible, but inconvenient and more costly at link time.
237
+
238
+ relocation_info pairedInfo = relInfos[i];
239
+ relocation_info relInfo =
240
+ target->isPairedReloc (pairedInfo) ? relInfos[++i] : pairedInfo;
241
+ assert (i < relInfos.size ());
242
+ if (relInfo.r_address & R_SCATTERED)
215
243
fatal (" TODO: Scattered relocations not supported" );
216
244
217
- auto relInfo = reinterpret_cast <const relocation_info &>(anyRelInfo);
218
-
219
245
Reloc r;
220
246
r.type = relInfo.r_type ;
221
247
r.pcrel = relInfo.r_pcrel ;
222
248
r.length = relInfo.r_length ;
223
- uint64_t rawAddend = target->getImplicitAddend (mb, sec, relInfo);
224
-
249
+ r.offset = relInfo.r_address ;
250
+ // For unpaired relocs, pairdInfo (just a copy of relInfo) is ignored
251
+ uint64_t rawAddend = target->getAddend (mb, sec, relInfo, pairedInfo);
225
252
if (relInfo.r_extern ) {
226
253
r.referent = symbols[relInfo.r_symbolnum ];
227
254
r.addend = rawAddend;
228
255
} else {
229
- if (relInfo.r_symbolnum == 0 || relInfo.r_symbolnum > subsections.size ())
230
- fatal (" invalid section index in relocation for offset " +
231
- std::to_string (r.offset ) + " in section " + sec.sectname +
232
- " of " + getName ());
233
-
234
256
SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1 ];
235
257
const section_64 &referentSec = sectionHeaders[relInfo.r_symbolnum - 1 ];
236
258
uint32_t referentOffset;
@@ -250,7 +272,6 @@ void ObjFile::parseRelocations(const section_64 &sec,
250
272
r.addend = referentOffset;
251
273
}
252
274
253
- r.offset = relInfo.r_address ;
254
275
InputSection *subsec = findContainingSubsection (subsecMap, &r.offset );
255
276
subsec->relocs .push_back (r);
256
277
}
0 commit comments