@@ -229,6 +229,19 @@ static const uint8_t tailMergeX64[] = {
229
229
0xFF , 0xE0 , // jmp rax
230
230
};
231
231
232
+ static const uint8_t tailMergeUnwindInfoX64[] = {
233
+ 0x01 , // Version=1, Flags=UNW_FLAG_NHANDLER
234
+ 0x0a , // Size of prolog
235
+ 0x05 , // Count of unwind codes
236
+ 0x00 , // No frame register
237
+ 0x0a , 0x82 , // Offset 0xa: UWOP_ALLOC_SMALL(0x48)
238
+ 0x06 , 0x02 , // Offset 6: UWOP_ALLOC_SMALL(8)
239
+ 0x04 , 0x02 , // Offset 4: UWOP_ALLOC_SMALL(8)
240
+ 0x02 , 0x02 , // Offset 2: UWOP_ALLOC_SMALL(8)
241
+ 0x01 , 0x02 , // Offset 1: UWOP_ALLOC_SMALL(8)
242
+ 0x00 , 0x00 // Padding to align on 32-bits
243
+ };
244
+
232
245
static const uint8_t thunkX86[] = {
233
246
0xB8 , 0 , 0 , 0 , 0 , // mov eax, offset ___imp__<FUNCNAME>
234
247
0xE9 , 0 , 0 , 0 , 0 , // jmp __tailMerge_<lib>
@@ -332,6 +345,41 @@ class TailMergeChunkX64 : public NonSectionChunk {
332
345
Defined *helper = nullptr ;
333
346
};
334
347
348
+ class TailMergePDataChunkX64 : public NonSectionChunk {
349
+ public:
350
+ TailMergePDataChunkX64 (Chunk *tm, Chunk *unwind) : tm(tm), unwind(unwind) {
351
+ // See
352
+ // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-runtime_function
353
+ setAlignment (4 );
354
+ }
355
+
356
+ size_t getSize () const override { return 3 * sizeof (uint32_t ); }
357
+
358
+ void writeTo (uint8_t *buf) const override {
359
+ write32le (buf + 0 , tm->getRVA ()); // TailMergeChunk start RVA
360
+ write32le (buf + 4 , tm->getRVA () + tm->getSize ()); // TailMergeChunk stop RVA
361
+ write32le (buf + 8 , unwind->getRVA ()); // UnwindInfo RVA
362
+ }
363
+
364
+ Chunk *tm = nullptr ;
365
+ Chunk *unwind = nullptr ;
366
+ };
367
+
368
+ class TailMergeUnwindInfoX64 : public NonSectionChunk {
369
+ public:
370
+ TailMergeUnwindInfoX64 () {
371
+ // See
372
+ // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
373
+ setAlignment (4 );
374
+ }
375
+
376
+ size_t getSize () const override { return sizeof (tailMergeUnwindInfoX64); }
377
+
378
+ void writeTo (uint8_t *buf) const override {
379
+ memcpy (buf, tailMergeUnwindInfoX64, sizeof (tailMergeUnwindInfoX64));
380
+ }
381
+ };
382
+
335
383
class ThunkChunkX86 : public NonSectionChunk {
336
384
public:
337
385
ThunkChunkX86 (COFFLinkerContext &ctx, Defined *i, Chunk *tm)
@@ -672,6 +720,8 @@ void DelayLoadContents::create(Defined *h) {
672
720
helper = h;
673
721
std::vector<std::vector<DefinedImportData *>> v = binImports (ctx, imports);
674
722
723
+ Chunk *unwind = newTailMergeUnwindInfoChunk ();
724
+
675
725
// Create .didat contents for each DLL.
676
726
for (std::vector<DefinedImportData *> &syms : v) {
677
727
// Create the delay import table header.
@@ -680,6 +730,7 @@ void DelayLoadContents::create(Defined *h) {
680
730
681
731
size_t base = addresses.size ();
682
732
Chunk *tm = newTailMergeChunk (dir);
733
+ Chunk *pdataChunk = unwind ? newTailMergePDataChunk (tm, unwind) : nullptr ;
683
734
for (DefinedImportData *s : syms) {
684
735
Chunk *t = newThunkChunk (s, tm);
685
736
auto *a = make<DelayAddressChunk>(ctx, t);
@@ -692,7 +743,7 @@ void DelayLoadContents::create(Defined *h) {
692
743
auto *c = make<HintNameChunk>(extName, 0 );
693
744
names.push_back (make<LookupChunk>(ctx, c));
694
745
hintNames.push_back (c);
695
- // Add a syntentic symbol for this load thunk, using the "__imp___load"
746
+ // Add a synthetic symbol for this load thunk, using the "__imp___load"
696
747
// prefix, in case this thunk needs to be added to the list of valid
697
748
// call targets for Control Flow Guard.
698
749
StringRef symName = saver ().save (" __imp___load_" + extName);
@@ -701,6 +752,8 @@ void DelayLoadContents::create(Defined *h) {
701
752
}
702
753
}
703
754
thunks.push_back (tm);
755
+ if (pdataChunk)
756
+ pdata.push_back (pdataChunk);
704
757
StringRef tmName =
705
758
saver ().save (" __tailMerge_" + syms[0 ]->getDLLName ().lower ());
706
759
ctx.symtab .addSynthetic (tmName, tm);
@@ -720,6 +773,9 @@ void DelayLoadContents::create(Defined *h) {
720
773
dir->nameTab = names[base];
721
774
dirs.push_back (dir);
722
775
}
776
+
777
+ if (unwind)
778
+ unwindinfo.push_back (unwind);
723
779
// Add null terminator.
724
780
dirs.push_back (make<NullChunk>(sizeof (delay_import_directory_table_entry)));
725
781
}
@@ -739,6 +795,25 @@ Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) {
739
795
}
740
796
}
741
797
798
+ Chunk *DelayLoadContents::newTailMergeUnwindInfoChunk () {
799
+ switch (ctx.config .machine ) {
800
+ case AMD64:
801
+ return make<TailMergeUnwindInfoX64>();
802
+ // FIXME: Add support for other architectures.
803
+ default :
804
+ return nullptr ; // Just don't generate unwind info.
805
+ }
806
+ }
807
+ Chunk *DelayLoadContents::newTailMergePDataChunk (Chunk *tm, Chunk *unwind) {
808
+ switch (ctx.config .machine ) {
809
+ case AMD64:
810
+ return make<TailMergePDataChunkX64>(tm, unwind);
811
+ // FIXME: Add support for other architectures.
812
+ default :
813
+ return nullptr ; // Just don't generate unwind info.
814
+ }
815
+ }
816
+
742
817
Chunk *DelayLoadContents::newThunkChunk (DefinedImportData *s,
743
818
Chunk *tailMerge) {
744
819
switch (ctx.config .machine ) {
0 commit comments