13
13
#include " lld/Common/ErrorHandler.h"
14
14
#include " lld/Common/LLVM.h"
15
15
#include " llvm/Support/LEB128.h"
16
+ #include " llvm/Support/xxhash.h"
16
17
17
18
#define DEBUG_TYPE " lld"
18
19
@@ -126,6 +127,10 @@ void InputChunk::writeTo(uint8_t *buf) const {
126
127
memcpy (buf + outSecOff, data ().data (), data ().size ());
127
128
128
129
// Apply relocations
130
+ relocate (buf + outSecOff);
131
+ }
132
+
133
+ void InputChunk::relocate (uint8_t *buf) const {
129
134
if (relocations.empty ())
130
135
return ;
131
136
@@ -135,11 +140,11 @@ void InputChunk::writeTo(uint8_t *buf) const {
135
140
136
141
LLVM_DEBUG (dbgs () << " applying relocations: " << toString (this )
137
142
<< " count=" << relocations.size () << " \n " );
138
- int32_t off = outSecOff - getInputSectionOffset ();
143
+ int32_t inputSectionOffset = getInputSectionOffset ();
139
144
auto tombstone = getTombstone ();
140
145
141
146
for (const WasmRelocation &rel : relocations) {
142
- uint8_t *loc = buf + rel.Offset + off ;
147
+ uint8_t *loc = buf + rel.Offset - inputSectionOffset ;
143
148
auto value = file->calcNewValue (rel, tombstone, this );
144
149
LLVM_DEBUG (dbgs () << " apply reloc: type=" << relocTypeToString (rel.Type ));
145
150
if (rel.Type != R_WASM_TYPE_INDEX_LEB)
@@ -357,8 +362,20 @@ void InputFunction::writeTo(uint8_t *buf) const {
357
362
LLVM_DEBUG (dbgs () << " total: " << (buf + chunkSize - orig) << " \n " );
358
363
}
359
364
365
+ uint64_t InputSegment::getOffset (uint64_t offset) const {
366
+ if (const MergeInputSegment *ms = dyn_cast<MergeInputSegment>(this )) {
367
+ LLVM_DEBUG (dbgs () << " getOffset(merged): " << getName () << " \n " );
368
+ LLVM_DEBUG (dbgs () << " offset: " << offset << " \n " );
369
+ LLVM_DEBUG (dbgs () << " parentOffset: " << ms->getParentOffset (offset)
370
+ << " \n " );
371
+ assert (ms->parent );
372
+ return ms->parent ->getOffset (ms->getParentOffset (offset));
373
+ }
374
+ return outputSegmentOffset + offset;
375
+ }
376
+
360
377
uint64_t InputSegment::getVA (uint64_t offset) const {
361
- return outputSeg->startVA + outputSegmentOffset + offset;
378
+ return ( outputSeg ? outputSeg ->startVA : 0 ) + getOffset ( offset) ;
362
379
}
363
380
364
381
// Generate code to apply relocations to the data section at runtime.
@@ -431,6 +448,93 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
431
448
}
432
449
}
433
450
451
+ // Split WASM_SEG_FLAG_STRINGS section. Such a section is a sequence of
452
+ // null-terminated strings.
453
+ void MergeInputSegment::splitStrings (ArrayRef<uint8_t > data) {
454
+ LLVM_DEBUG (llvm::dbgs () << " splitStrings\n " );
455
+ size_t off = 0 ;
456
+ StringRef s = toStringRef (data);
457
+
458
+ while (!s.empty ()) {
459
+ size_t end = s.find (0 );
460
+ if (end == StringRef::npos)
461
+ fatal (toString (this ) + " : string is not null terminated" );
462
+ size_t size = end + 1 ;
463
+
464
+ pieces.emplace_back (off, xxHash64 (s.substr (0 , size)), true );
465
+ s = s.substr (size);
466
+ off += size;
467
+ }
468
+ }
469
+
470
+ // This function is called after we obtain a complete list of input sections
471
+ // that need to be linked. This is responsible to split section contents
472
+ // into small chunks for further processing.
473
+ //
474
+ // Note that this function is called from parallelForEach. This must be
475
+ // thread-safe (i.e. no memory allocation from the pools).
476
+ void MergeInputSegment::splitIntoPieces () {
477
+ assert (pieces.empty ());
478
+ // As of now we only support WASM_SEG_FLAG_STRINGS but in the future we
479
+ // could add other types of splitting (see ELF's splitIntoPieces).
480
+ assert (segment->Data .LinkingFlags & WASM_SEG_FLAG_STRINGS);
481
+ splitStrings (data ());
482
+ }
483
+
484
+ SegmentPiece *MergeInputSegment::getSegmentPiece (uint64_t offset) {
485
+ if (this ->data ().size () <= offset)
486
+ fatal (toString (this ) + " : offset is outside the section" );
487
+
488
+ // If Offset is not at beginning of a section piece, it is not in the map.
489
+ // In that case we need to do a binary search of the original section piece
490
+ // vector.
491
+ auto it = partition_point (
492
+ pieces, [=](SegmentPiece p) { return p.inputOff <= offset; });
493
+ return &it[-1 ];
494
+ }
495
+
496
+ // Returns the offset in an output section for a given input offset.
497
+ // Because contents of a mergeable section is not contiguous in output,
498
+ // it is not just an addition to a base output offset.
499
+ uint64_t MergeInputSegment::getParentOffset (uint64_t offset) const {
500
+ // If Offset is not at beginning of a section piece, it is not in the map.
501
+ // In that case we need to search from the original section piece vector.
502
+ const SegmentPiece *piece = getSegmentPiece (offset);
503
+ uint64_t addend = offset - piece->inputOff ;
504
+ return piece->outputOff + addend;
505
+ }
506
+
507
+ uint32_t SyntheticMergedDataSegment::getSize () const {
508
+ return builder.getSize ();
509
+ }
510
+
511
+ void SyntheticMergedDataSegment::writeTo (uint8_t *buf) const {
512
+ builder.write (buf + outSecOff);
513
+
514
+ // Apply relocations
515
+ relocate (buf + outSecOff);
516
+ }
517
+
518
+ void SyntheticMergedDataSegment::finalizeContents () {
519
+ // Add all string pieces to the string table builder to create section
520
+ // contents.
521
+ for (MergeInputSegment *sec : segments)
522
+ for (size_t i = 0 , e = sec->pieces .size (); i != e; ++i)
523
+ if (sec->pieces [i].live )
524
+ builder.add (sec->getData (i));
525
+
526
+ // Fix the string table content. After this, the contents will never change.
527
+ builder.finalize ();
528
+
529
+ // finalize() fixed tail-optimized strings, so we can now get
530
+ // offsets of strings. Get an offset for each string and save it
531
+ // to a corresponding SectionPiece for easy access.
532
+ for (MergeInputSegment *sec : segments)
533
+ for (size_t i = 0 , e = sec->pieces .size (); i != e; ++i)
534
+ if (sec->pieces [i].live )
535
+ sec->pieces [i].outputOff = builder.getOffset (sec->getData (i));
536
+ }
537
+
434
538
uint64_t InputSection::getTombstoneForSection (StringRef name) {
435
539
// When a function is not live we need to update relocations referring to it.
436
540
// If they occur in DWARF debug symbols, we want to change the pc of the
0 commit comments