@@ -40,11 +40,6 @@ struct MipsRelocationEntry {
40
40
bool Matched = false ; // /< Is this relocation part of a match.
41
41
42
42
MipsRelocationEntry (const ELFRelocationEntry &R) : R(R) {}
43
-
44
- void print (raw_ostream &Out) const {
45
- R.print (Out);
46
- Out << " , Matched=" << Matched;
47
- }
48
43
};
49
44
50
45
class MipsELFObjectWriter : public MCELFObjectTargetWriter {
@@ -134,8 +129,7 @@ static unsigned getMatchingLoType(const ELFRelocationEntry &Reloc) {
134
129
if (Type == ELF::R_MIPS16_HI16)
135
130
return ELF::R_MIPS16_LO16;
136
131
137
- if (Reloc.OriginalSymbol &&
138
- Reloc.OriginalSymbol ->getBinding () != ELF::STB_LOCAL)
132
+ if (Reloc.Symbol && Reloc.Symbol ->getBinding () != ELF::STB_LOCAL)
139
133
return ELF::R_MIPS_NONE;
140
134
141
135
if (Type == ELF::R_MIPS_GOT16)
@@ -148,43 +142,11 @@ static unsigned getMatchingLoType(const ELFRelocationEntry &Reloc) {
148
142
return ELF::R_MIPS_NONE;
149
143
}
150
144
151
- // / Determine whether a relocation (X) matches the one given in R.
152
- // /
153
- // / A relocation matches if:
154
- // / - It's type matches that of a corresponding low part. This is provided in
155
- // / MatchingType for efficiency.
156
- // / - It's based on the same symbol.
157
- // / - It's offset of greater or equal to that of the one given in R.
158
- // / It should be noted that this rule assumes the programmer does not use
159
- // / offsets that exceed the alignment of the symbol. The carry-bit will be
160
- // / incorrect if this is not true.
161
- // /
162
- // / A matching relocation is unbeatable if:
163
- // / - It is not already involved in a match.
164
- // / - It's offset is exactly that of the one given in R.
165
- static FindBestPredicateResult isMatchingReloc (const MipsRelocationEntry &X,
166
- const ELFRelocationEntry &R,
167
- unsigned MatchingType) {
168
- if (X.R .Type == MatchingType && X.R .OriginalSymbol == R.OriginalSymbol ) {
169
- if (!X.Matched && X.R .Addend == R.Addend )
170
- return FindBest_PerfectMatch;
171
- else if (X.R .Addend >= R.Addend )
172
- return FindBest_Match;
173
- }
174
- return FindBest_NoMatch;
175
- }
176
-
177
- // / Determine whether Candidate or PreviousBest is the better match.
178
- // / The return value is true if Candidate is the better match.
179
- // /
180
- // / A matching relocation is a better match if:
181
- // / - It has a smaller addend.
182
- // / - It is not already involved in a match.
183
- static bool compareMatchingRelocs (const MipsRelocationEntry &Candidate,
184
- const MipsRelocationEntry &PreviousBest) {
185
- if (Candidate.R .Addend != PreviousBest.R .Addend )
186
- return Candidate.R .Addend < PreviousBest.R .Addend ;
187
- return PreviousBest.Matched && !Candidate.Matched ;
145
+ // Determine whether a relocation X is a low-part and matches the high-part R
146
+ // perfectly by symbol and addend.
147
+ static bool isMatchingReloc (unsigned MatchingType, const ELFRelocationEntry &R,
148
+ const ELFRelocationEntry &X) {
149
+ return X.Type == MatchingType && X.Symbol == R.Symbol && X.Addend == R.Addend ;
188
150
}
189
151
190
152
MipsELFObjectWriter::MipsELFObjectWriter (uint8_t OSABI,
@@ -413,58 +375,51 @@ void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
413
375
if (hasRelocationAddend ())
414
376
return ;
415
377
416
- if (Relocs.size () < 2 )
417
- return ;
418
-
419
378
// Sort relocations by the address they are applied to.
420
379
llvm::sort (Relocs,
421
380
[](const ELFRelocationEntry &A, const ELFRelocationEntry &B) {
422
381
return A.Offset < B.Offset ;
423
382
});
424
383
384
+ // Place relocations in a list for reorder convenience. Hi16 contains the
385
+ // iterators of high-part relocations.
425
386
std::list<MipsRelocationEntry> Sorted;
426
- std::list<ELFRelocationEntry> Remainder;
427
-
428
- // Separate the movable relocations (AHL relocations using the high bits) from
429
- // the immobile relocations (everything else). This does not preserve high/low
430
- // matches that already existed in the input.
431
- copy_if_else (Relocs.begin (), Relocs.end (), std::back_inserter (Remainder),
432
- std::back_inserter (Sorted), [](const ELFRelocationEntry &Reloc) {
433
- return getMatchingLoType (Reloc) != ELF::R_MIPS_NONE;
434
- });
387
+ SmallVector<std::list<MipsRelocationEntry>::iterator, 0 > Hi16;
388
+ for (auto &R : Relocs) {
389
+ Sorted.push_back (R);
390
+ if (getMatchingLoType (R) != ELF::R_MIPS_NONE)
391
+ Hi16.push_back (std::prev (Sorted.end ()));
392
+ }
435
393
436
- for (auto &R : Remainder) {
394
+ for (auto I : Hi16) {
395
+ auto &R = I->R ;
437
396
unsigned MatchingType = getMatchingLoType (R);
438
- assert (MatchingType != ELF::R_MIPS_NONE &&
439
- " Wrong list for reloc that doesn't need a match" );
440
-
441
- // Find the best matching relocation for the current high part.
442
- // See isMatchingReloc for a description of a matching relocation and
443
- // compareMatchingRelocs for a description of what 'best' means.
444
- auto InsertionPoint =
445
- find_best (Sorted.begin (), Sorted.end (),
446
- [&R, &MatchingType](const MipsRelocationEntry &X) {
447
- return isMatchingReloc (X, R, MatchingType);
448
- },
449
- compareMatchingRelocs);
450
-
451
- // If we matched then insert the high part in front of the match and mark
452
- // both relocations as being involved in a match. We only mark the high
453
- // part for cosmetic reasons in the debug output.
397
+ // If the next relocation is a perfect match, continue;
398
+ if (std::next (I) != Sorted.end () &&
399
+ isMatchingReloc (MatchingType, R, std::next (I)->R ))
400
+ continue ;
401
+ // Otherwise, find the best matching low-part relocation with the following
402
+ // criteria. It must have the same symbol and its addend is no lower than
403
+ // that of the current high-part.
454
404
//
455
- // If we failed to find a match then the high part is orphaned. This is not
456
- // permitted since the relocation cannot be evaluated without knowing the
457
- // carry-in. We can sometimes handle this using a matching low part that is
458
- // already used in a match but we already cover that case in
459
- // isMatchingReloc and compareMatchingRelocs. For the remaining cases we
460
- // should insert the high part at the end of the list. This will cause the
461
- // linker to fail but the alternative is to cause the linker to bind the
462
- // high part to a semi-matching low part and silently calculate the wrong
463
- // value. Unfortunately we have no means to warn the user that we did this
464
- // so leave it up to the linker to complain about it.
465
- if (InsertionPoint != Sorted.end ())
466
- InsertionPoint->Matched = true ;
467
- Sorted.insert (InsertionPoint, R)->Matched = true ;
405
+ // (1) %lo with a smaller offset is preferred.
406
+ // (2) %lo with the same offset that is unmatched is preferred.
407
+ // (3) later %lo is preferred.
408
+ auto Best = Sorted.end ();
409
+ for (auto J = Sorted.begin (); J != Sorted.end (); ++J) {
410
+ auto &R1 = J->R ;
411
+ if (R1.Type == MatchingType && R.Symbol == R1.Symbol &&
412
+ R.Addend <= R1.Addend &&
413
+ (Best == Sorted.end () || R1.Addend < Best->R .Addend ||
414
+ (!Best->Matched && R1.Addend == Best->R .Addend )))
415
+ Best = J;
416
+ }
417
+ if (Best != Sorted.end () && R.Addend == Best->R .Addend )
418
+ Best->Matched = true ;
419
+
420
+ // Move the high-part before the low-part, or if not found, the end of the
421
+ // list. The unmatched high-part will lead to a linker warning/error.
422
+ Sorted.splice (Best, Sorted, I);
468
423
}
469
424
470
425
assert (Relocs.size () == Sorted.size () && " Some relocs were not consumed" );
0 commit comments