Skip to content

Conversation

@cjacek
Copy link
Contributor

@cjacek cjacek commented Nov 13, 2023

Filling entire buffer would require all chunks to overwrite it later, which is not the case for uninitialized chunks merged into a code section.

Fixes the problem I mentioned in #72030.

@llvmbot
Copy link
Member

llvmbot commented Nov 13, 2023

@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-lld

Author: Jacek Caban (cjacek)

Changes

Filling entire buffer would require all chunks to overwrite it later, which is not the case for uninitialized chunks merged into a code section.

Fixes the problem I mentioned in #72030.


Full diff: https://github.com/llvm/llvm-project/pull/72138.diff

2 Files Affected:

  • (modified) lld/COFF/Writer.cpp (+10-2)
  • (added) lld/test/COFF/code-merge.s (+146)
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 218a4f336fedc6f..be7265cfc194411 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -2021,8 +2021,16 @@ void Writer::writeSections() {
     // instead of leaving as NUL bytes (which can be interpreted as
     // ADD instructions).
     if ((sec->header.Characteristics & IMAGE_SCN_CNT_CODE) &&
-        (ctx.config.machine == AMD64 || ctx.config.machine == I386))
-      memset(secBuf, 0xCC, sec->getRawSize());
+        (ctx.config.machine == AMD64 || ctx.config.machine == I386)) {
+      uint32_t prevEnd = 0;
+      for (Chunk *c : sec->chunks) {
+        uint32_t off = c->getRVA() - sec->getRVA();
+        memset(secBuf + prevEnd, 0xCC, off - prevEnd);
+        prevEnd = off + c->getSize();
+      }
+      memset(secBuf + prevEnd, 0xCC, sec->getRawSize() - prevEnd);
+    }
+
     parallelForEach(sec->chunks, [&](Chunk *c) {
       c->writeTo(secBuf + c->getRVA() - sec->getRVA());
     });
diff --git a/lld/test/COFF/code-merge.s b/lld/test/COFF/code-merge.s
new file mode 100644
index 000000000000000..e7aa86533ce547a
--- /dev/null
+++ b/lld/test/COFF/code-merge.s
@@ -0,0 +1,146 @@
+# REQUIRES: x86
+
+# Test merging code sections with data sections.
+
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link -machine:amd64 -dll -noentry -out:%t.dll %t.obj -merge:.testx=.testd -merge:.testx2=.testbss -merge:.testd2=.testx3 -merge:.testbss2=.testx4
+
+# RUN: llvm-readobj --sections %t.dll | FileCheck %s
+# CHECK:      Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 1
+# CHECK-NEXT:     Name: .testbss (2E 74 65 73 74 62 73 73)
+# CHECK-NEXT:     VirtualSize: 0x18
+# CHECK-NEXT:     VirtualAddress: 0x1000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0x400
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0xC0000080)
+# CHECK-NEXT:       IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:       IMAGE_SCN_MEM_WRITE (0x80000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 2
+# CHECK-NEXT:     Name: .testd (2E 74 65 73 74 64 00 00)
+# CHECK-NEXT:     VirtualSize: 0x18
+# CHECK-NEXT:     VirtualAddress: 0x2000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0x600
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0x40000040)
+# CHECK-NEXT:       IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 3
+# CHECK-NEXT:     Name: .testx3 (2E 74 65 73 74 78 33 00)
+# CHECK-NEXT:     VirtualSize: 0x12
+# CHECK-NEXT:     VirtualAddress: 0x3000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0x800
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0x60000020)
+# CHECK-NEXT:       IMAGE_SCN_CNT_CODE (0x20)
+# CHECK-NEXT:       IMAGE_SCN_MEM_EXECUTE (0x20000000)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 4
+# CHECK-NEXT:     Name: .testx4 (2E 74 65 73 74 78 34 00)
+# CHECK-NEXT:     VirtualSize: 0x14
+# CHECK-NEXT:     VirtualAddress: 0x4000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0xA00
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0x60000020)
+# CHECK-NEXT:       IMAGE_SCN_CNT_CODE (0x20)
+# CHECK-NEXT:       IMAGE_SCN_MEM_EXECUTE (0x20000000)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# RUN: llvm-objdump -d %t.dll | FileCheck -check-prefix=DISASM %s
+# DISASM:      Disassembly of section .testx3:
+# DISASM-EMPTY:
+# DISASM-NEXT: 0000000180003000 <.testx3>:
+# DISASM-NEXT: 180003000: 48 c7 c0 03 00 00 00         movq    $0x3, %rax
+# DISASM-NEXT: 180003007: c3                           retq
+# DISASM-NEXT: 180003008: cc                           int3
+# DISASM-NEXT: 180003009: cc                           int3
+# DISASM-NEXT: 18000300a: cc                           int3
+# DISASM-NEXT: 18000300b: cc                           int3
+# DISASM-NEXT: 18000300c: cc                           int3
+# DISASM-NEXT: 18000300d: cc                           int3
+# DISASM-NEXT: 18000300e: cc                           int3
+# DISASM-NEXT: 18000300f: cc                           int3
+# DISASM-NEXT: 180003010: 02 00                        addb    (%rax), %al
+# DISASM-EMPTY:
+# DISASM-NEXT: Disassembly of section .testx4:
+# DISASM-EMPTY:
+# DISASM-NEXT: 0000000180004000 <.testx4>:
+# DISASM-NEXT: 180004000: 48 c7 c0 04 00 00 00         movq    $0x4, %rax
+# DISASM-NEXT: 180004007: c3                           retq
+# DISASM-NEXT: 180004008: cc                           int3
+# DISASM-NEXT: 180004009: cc                           int3
+# DISASM-NEXT: 18000400a: cc                           int3
+# DISASM-NEXT: 18000400b: cc                           int3
+# DISASM-NEXT: 18000400c: cc                           int3
+# DISASM-NEXT: 18000400d: cc                           int3
+# DISASM-NEXT: 18000400e: cc                           int3
+# DISASM-NEXT: 18000400f: cc                           int3
+# DISASM-NEXT: 180004010: 00 00                        addb    %al, (%rax)
+# DISASM-NEXT: 180004012: 00 00                        addb    %al, (%rax)
+
+
+        .section .testx, "xr"
+        .p2align 4
+        movq $1, %rax
+        retq
+
+        .section .testx2, "xr"
+        .p2align 4
+        movq $2, %rax
+        retq
+
+        .section .testd, "dr"
+        .p2align 4
+        .word 1
+
+        .section .testbss, "b"
+        .p2align 4
+        .skip 4
+
+        .section .testx3, "xr"
+        .p2align 4
+        movq $3, %rax
+        retq
+
+        .section .testx4, "xr"
+        .p2align 4
+        movq $4, %rax
+        retq
+
+        .section .testd2, "dr"
+        .p2align 4
+        .word 2
+
+        .section .testbss2, "b"
+        .p2align 4
+        .skip 4

@llvmbot
Copy link
Member

llvmbot commented Nov 13, 2023

@llvm/pr-subscribers-lld-coff

Author: Jacek Caban (cjacek)

Changes

Filling entire buffer would require all chunks to overwrite it later, which is not the case for uninitialized chunks merged into a code section.

Fixes the problem I mentioned in #72030.


Full diff: https://github.com/llvm/llvm-project/pull/72138.diff

2 Files Affected:

  • (modified) lld/COFF/Writer.cpp (+10-2)
  • (added) lld/test/COFF/code-merge.s (+146)
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 218a4f336fedc6f..be7265cfc194411 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -2021,8 +2021,16 @@ void Writer::writeSections() {
     // instead of leaving as NUL bytes (which can be interpreted as
     // ADD instructions).
     if ((sec->header.Characteristics & IMAGE_SCN_CNT_CODE) &&
-        (ctx.config.machine == AMD64 || ctx.config.machine == I386))
-      memset(secBuf, 0xCC, sec->getRawSize());
+        (ctx.config.machine == AMD64 || ctx.config.machine == I386)) {
+      uint32_t prevEnd = 0;
+      for (Chunk *c : sec->chunks) {
+        uint32_t off = c->getRVA() - sec->getRVA();
+        memset(secBuf + prevEnd, 0xCC, off - prevEnd);
+        prevEnd = off + c->getSize();
+      }
+      memset(secBuf + prevEnd, 0xCC, sec->getRawSize() - prevEnd);
+    }
+
     parallelForEach(sec->chunks, [&](Chunk *c) {
       c->writeTo(secBuf + c->getRVA() - sec->getRVA());
     });
diff --git a/lld/test/COFF/code-merge.s b/lld/test/COFF/code-merge.s
new file mode 100644
index 000000000000000..e7aa86533ce547a
--- /dev/null
+++ b/lld/test/COFF/code-merge.s
@@ -0,0 +1,146 @@
+# REQUIRES: x86
+
+# Test merging code sections with data sections.
+
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link -machine:amd64 -dll -noentry -out:%t.dll %t.obj -merge:.testx=.testd -merge:.testx2=.testbss -merge:.testd2=.testx3 -merge:.testbss2=.testx4
+
+# RUN: llvm-readobj --sections %t.dll | FileCheck %s
+# CHECK:      Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 1
+# CHECK-NEXT:     Name: .testbss (2E 74 65 73 74 62 73 73)
+# CHECK-NEXT:     VirtualSize: 0x18
+# CHECK-NEXT:     VirtualAddress: 0x1000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0x400
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0xC0000080)
+# CHECK-NEXT:       IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:       IMAGE_SCN_MEM_WRITE (0x80000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 2
+# CHECK-NEXT:     Name: .testd (2E 74 65 73 74 64 00 00)
+# CHECK-NEXT:     VirtualSize: 0x18
+# CHECK-NEXT:     VirtualAddress: 0x2000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0x600
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0x40000040)
+# CHECK-NEXT:       IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 3
+# CHECK-NEXT:     Name: .testx3 (2E 74 65 73 74 78 33 00)
+# CHECK-NEXT:     VirtualSize: 0x12
+# CHECK-NEXT:     VirtualAddress: 0x3000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0x800
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0x60000020)
+# CHECK-NEXT:       IMAGE_SCN_CNT_CODE (0x20)
+# CHECK-NEXT:       IMAGE_SCN_MEM_EXECUTE (0x20000000)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Number: 4
+# CHECK-NEXT:     Name: .testx4 (2E 74 65 73 74 78 34 00)
+# CHECK-NEXT:     VirtualSize: 0x14
+# CHECK-NEXT:     VirtualAddress: 0x4000
+# CHECK-NEXT:     RawDataSize: 512
+# CHECK-NEXT:     PointerToRawData: 0xA00
+# CHECK-NEXT:     PointerToRelocations: 0x0
+# CHECK-NEXT:     PointerToLineNumbers: 0x0
+# CHECK-NEXT:     RelocationCount: 0
+# CHECK-NEXT:     LineNumberCount: 0
+# CHECK-NEXT:     Characteristics [ (0x60000020)
+# CHECK-NEXT:       IMAGE_SCN_CNT_CODE (0x20)
+# CHECK-NEXT:       IMAGE_SCN_MEM_EXECUTE (0x20000000)
+# CHECK-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# RUN: llvm-objdump -d %t.dll | FileCheck -check-prefix=DISASM %s
+# DISASM:      Disassembly of section .testx3:
+# DISASM-EMPTY:
+# DISASM-NEXT: 0000000180003000 <.testx3>:
+# DISASM-NEXT: 180003000: 48 c7 c0 03 00 00 00         movq    $0x3, %rax
+# DISASM-NEXT: 180003007: c3                           retq
+# DISASM-NEXT: 180003008: cc                           int3
+# DISASM-NEXT: 180003009: cc                           int3
+# DISASM-NEXT: 18000300a: cc                           int3
+# DISASM-NEXT: 18000300b: cc                           int3
+# DISASM-NEXT: 18000300c: cc                           int3
+# DISASM-NEXT: 18000300d: cc                           int3
+# DISASM-NEXT: 18000300e: cc                           int3
+# DISASM-NEXT: 18000300f: cc                           int3
+# DISASM-NEXT: 180003010: 02 00                        addb    (%rax), %al
+# DISASM-EMPTY:
+# DISASM-NEXT: Disassembly of section .testx4:
+# DISASM-EMPTY:
+# DISASM-NEXT: 0000000180004000 <.testx4>:
+# DISASM-NEXT: 180004000: 48 c7 c0 04 00 00 00         movq    $0x4, %rax
+# DISASM-NEXT: 180004007: c3                           retq
+# DISASM-NEXT: 180004008: cc                           int3
+# DISASM-NEXT: 180004009: cc                           int3
+# DISASM-NEXT: 18000400a: cc                           int3
+# DISASM-NEXT: 18000400b: cc                           int3
+# DISASM-NEXT: 18000400c: cc                           int3
+# DISASM-NEXT: 18000400d: cc                           int3
+# DISASM-NEXT: 18000400e: cc                           int3
+# DISASM-NEXT: 18000400f: cc                           int3
+# DISASM-NEXT: 180004010: 00 00                        addb    %al, (%rax)
+# DISASM-NEXT: 180004012: 00 00                        addb    %al, (%rax)
+
+
+        .section .testx, "xr"
+        .p2align 4
+        movq $1, %rax
+        retq
+
+        .section .testx2, "xr"
+        .p2align 4
+        movq $2, %rax
+        retq
+
+        .section .testd, "dr"
+        .p2align 4
+        .word 1
+
+        .section .testbss, "b"
+        .p2align 4
+        .skip 4
+
+        .section .testx3, "xr"
+        .p2align 4
+        movq $3, %rax
+        retq
+
+        .section .testx4, "xr"
+        .p2align 4
+        movq $4, %rax
+        retq
+
+        .section .testd2, "dr"
+        .p2align 4
+        .word 2
+
+        .section .testbss2, "b"
+        .p2align 4
+        .skip 4

Copy link
Member

@mstorsjo mstorsjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, this seems mostly straightforward.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be nice to leave a comment here, saying what this does. E.g. something like this? "Only fill the gaps between chunks. Most chunks overwrite it anyway, but uninitialized data chunks merged into a code section don't."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks!

Filling entire buffer would require all chunks to overwrite it later, which is not the case for uninitialized chunks merged into a code section.
@cjacek cjacek merged commit 54f83e6 into llvm:main Nov 14, 2023
@cjacek cjacek deleted the lld-fill-gaps branch November 14, 2023 19:48
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
Filling entire buffer would require all chunks to overwrite it later,
which is not the case for uninitialized chunks merged into code
sections.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants