[lld] aaf3a8d - [LLD][COFF] Add -build-id flag to generate .buildid section. (#71433)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 5 11:57:49 PST 2023
Author: Zequan Wu
Date: 2023-12-05T14:57:45-05:00
New Revision: aaf3a8ded47121c8ec8136f97a7a2c39112b3e59
URL: https://github.com/llvm/llvm-project/commit/aaf3a8ded47121c8ec8136f97a7a2c39112b3e59
DIFF: https://github.com/llvm/llvm-project/commit/aaf3a8ded47121c8ec8136f97a7a2c39112b3e59.diff
LOG: [LLD][COFF] Add -build-id flag to generate .buildid section. (#71433)
[RFC](https://discourse.llvm.org/t/rfc-add-build-id-flag-to-lld-link/74661)
Before, lld-link only generate the debug directory containing guid when
generating PDB with the hash of PDB content.
With this change, lld-link can generate the debug directory when only
`/build-id` is given:
1. If generating PDB, `/build-id` is ignored. Same behaviour as before.
2. Not generating PDB, using hash of the binary.
- Not under MinGW, the debug directory is still in `.rdata` section.
- Under MinGW, place the debug directory into new `.buildid` section.
Added:
Modified:
lld/COFF/Config.h
lld/COFF/Driver.cpp
lld/COFF/Options.td
lld/COFF/Writer.cpp
lld/MinGW/Driver.cpp
lld/MinGW/Options.td
lld/test/COFF/debug-reloc.s
lld/test/COFF/rsds.test
lld/test/MinGW/driver.test
Removed:
################################################################################
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index bee6dc3ec3cae..24126f635a06f 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -102,6 +102,12 @@ enum class ICFLevel {
// behavior.
};
+enum class BuildIDHash {
+ None,
+ PDB,
+ Binary,
+};
+
// Global configuration.
struct Configuration {
enum ManifestKind { Default, SideBySide, Embed, No };
@@ -318,6 +324,7 @@ struct Configuration {
bool writeCheckSum = false;
EmitKind emit = EmitKind::Obj;
bool allowDuplicateWeak = false;
+ BuildIDHash buildIDHash = BuildIDHash::None;
};
} // namespace lld::coff
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 5181520c0917e..99c1a60735adc 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2314,6 +2314,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
config->lldmapFile.clear();
}
+ // If should create PDB, use the hash of PDB content for build id. Otherwise,
+ // generate using the hash of executable content.
+ if (args.hasFlag(OPT_build_id, OPT_build_id_no, false))
+ config->buildIDHash = BuildIDHash::Binary;
+
if (shouldCreatePDB) {
// Put the PDB next to the image if no /pdb flag was passed.
if (config->pdbPath.empty()) {
@@ -2335,6 +2340,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Don't do this earlier, so that ctx.OutputFile is ready.
parsePDBAltPath();
}
+ config->buildIDHash = BuildIDHash::PDB;
}
// Set default image base if /base is not given.
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index abee660272689..4dab4a2071739 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -302,6 +302,11 @@ def : Flag<["--"], "time-trace">, Alias<time_trace_eq>,
def time_trace_granularity_eq: Joined<["--"], "time-trace-granularity=">,
HelpText<"Minimum time granularity (in microseconds) traced by time profiler">;
+defm build_id: B<
+ "build-id",
+ "Generate build ID (always on when generating PDB)",
+ "Do not Generate build ID">;
+
// Flags for debugging
def lldmap : F<"lldmap">;
def lldmap_file : P_priv<"lldmap">;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index d6b1dbc8cc225..7b1ff8071e2e3 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -315,6 +315,8 @@ class Writer {
OutputSection *relocSec;
OutputSection *ctorsSec;
OutputSection *dtorsSec;
+ // Either .rdata section or .buildid section.
+ OutputSection *debugInfoSec;
// The range of .pdata sections in the output file.
//
@@ -1103,15 +1105,16 @@ void Writer::createMiscChunks() {
}
// Create Debug Information Chunks
- OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec;
- if (config->debug || config->repro || config->cetCompat) {
+ debugInfoSec = config->mingw ? buildidSec : rdataSec;
+ if (config->buildIDHash != BuildIDHash::None || config->debug ||
+ config->repro || config->cetCompat) {
debugDirectory =
make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);
debugDirectory->setAlignment(4);
debugInfoSec->addChunk(debugDirectory);
}
- if (config->debug) {
+ if (config->debug || config->buildIDHash != BuildIDHash::None) {
// Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We
// output a PDB no matter what, and this chunk provides the only means of
// allowing a debugger to match a PDB and an executable. So we need it even
@@ -2170,8 +2173,8 @@ void Writer::writeBuildId() {
// For reproducibility, instead of a timestamp we want to use a hash of the
// PE contents.
Configuration *config = &ctx.config;
-
- if (config->debug) {
+ bool generateSyntheticBuildId = config->buildIDHash == BuildIDHash::Binary;
+ if (generateSyntheticBuildId) {
assert(buildId && "BuildId is not set!");
// BuildId->BuildId was filled in when the PDB was written.
}
@@ -2186,8 +2189,6 @@ void Writer::writeBuildId() {
uint32_t timestamp = config->timestamp;
uint64_t hash = 0;
- bool generateSyntheticBuildId =
- config->mingw && config->debug && config->pdbPath.empty();
if (config->repro || generateSyntheticBuildId)
hash = xxh3_64bits(outputFileData);
@@ -2196,8 +2197,6 @@ void Writer::writeBuildId() {
timestamp = static_cast<uint32_t>(hash);
if (generateSyntheticBuildId) {
- // For MinGW builds without a PDB file, we still generate a build id
- // to allow associating a crash dump to the executable.
buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70;
buildId->buildId->PDB70.Age = 1;
memcpy(buildId->buildId->PDB70.Signature, &hash, 8);
diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp
index 19bf2d1617057..d22b617cf2f01 100644
--- a/lld/MinGW/Driver.cpp
+++ b/lld/MinGW/Driver.cpp
@@ -302,6 +302,21 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
} else if (!args.hasArg(OPT_strip_all)) {
add("-debug:dwarf");
}
+ if (auto *a = args.getLastArg(OPT_build_id)) {
+ StringRef v = a->getValue();
+ if (v == "none")
+ add("-build-id:no");
+ else {
+ if (!v.empty())
+ warn("unsupported build id hashing: " + v + ", using default hashing.");
+ add("-build-id");
+ }
+ } else {
+ if (args.hasArg(OPT_strip_debug) || args.hasArg(OPT_strip_all))
+ add("-build-id:no");
+ else
+ add("-build-id");
+ }
if (args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false))
add("-WX");
diff --git a/lld/MinGW/Options.td b/lld/MinGW/Options.td
index fa4c4ecc75d65..d4a49cdbd5359 100644
--- a/lld/MinGW/Options.td
+++ b/lld/MinGW/Options.td
@@ -196,6 +196,9 @@ defm guard_longjmp : B<"guard-longjmp",
"Do not enable Control Flow Guard long jump hardening">;
defm error_limit:
EqLong<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">;
+def build_id: J<"build-id=">, HelpText<"Generate build ID note (pass none to disable)">,
+ MetaVarName<"<arg>">;
+def : F<"build-id">, Alias<build_id>, HelpText<"Alias for --build-id=">;
// Alias
def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias<Bdynamic>;
@@ -213,7 +216,6 @@ def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
// Ignored options
def: Joined<["-"], "O">;
def: F<"as-needed">;
-def: F<"build-id">;
def: F<"disable-auto-image-base">;
def: F<"enable-auto-image-base">;
def: F<"end-group">;
diff --git a/lld/test/COFF/debug-reloc.s b/lld/test/COFF/debug-reloc.s
index bdf2563156540..68992414bd97c 100644
--- a/lld/test/COFF/debug-reloc.s
+++ b/lld/test/COFF/debug-reloc.s
@@ -2,7 +2,7 @@
# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
-# RUN: lld-link -lldmingw -debug:dwarf -out:%t.exe -entry:mainfunc -subsystem:console %t.obj
+# RUN: lld-link -lldmingw -debug:dwarf -build-id -out:%t.exe -entry:mainfunc -subsystem:console %t.obj
# RUN: llvm-readobj --sections %t.exe | FileCheck %s -check-prefix SECTIONS
# RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck %s -check-prefix RELOCS
# RUN: llvm-readobj --file-headers %t.exe | FileCheck %s -check-prefix HEADERS
diff --git a/lld/test/COFF/rsds.test b/lld/test/COFF/rsds.test
index 475249ca40566..3b611c091e2ef 100644
--- a/lld/test/COFF/rsds.test
+++ b/lld/test/COFF/rsds.test
@@ -22,9 +22,30 @@
# RUN: lld-link /Brepro /debug /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix REPRODEBUG %s
+# Generate .buildid section using binary hash under /lldmingw and /build-id
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /lldmingw /debug:dwarf /dll /out:%t.dll /entry:DllMain %t.obj
-# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix MINGW %s
+# RUN: lld-link /lldmingw /build-id /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix BUILDID %s
+
+# Generate debug directory with use binary hash when /build-id is given and not
+# generating PDB.
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /build-id /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix BUILDID %s
+
+# If generate PDB, PDB hash is used and /build-id is ignored.
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /build-id /debug /pdbaltpath:test.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix BUILDID %s
+
+# Do not generate .buildid section under /build-id:no
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /build-id:no /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix NO_BUILDID %s
+
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix NO_BUILDID %s
# CHECK: File: [[FILE:.*]].dll
# CHECK: DebugDirectory [
@@ -148,25 +169,30 @@
# REPRODEBUG: }
# REPRODEBUG: ]
-# MINGW: File: {{.*}}.dll
-# MINGW: DebugDirectory [
-# MINGW: DebugEntry {
-# MINGW: Characteristics: 0x0
-# MINGW: TimeDateStamp:
-# MINGW: MajorVersion: 0x0
-# MINGW: MinorVersion: 0x0
-# MINGW: Type: CodeView (0x2)
-# MINGW: SizeOfData: 0x{{[^0]}}
-# MINGW: AddressOfRawData: 0x{{[^0]}}
-# MINGW: PointerToRawData: 0x{{[^0]}}
-# MINGW: PDBInfo {
-# MINGW: PDBSignature: 0x53445352
-# MINGW: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
-# MINGW: PDBAge: 1
-# MINGW: PDBFileName:
-# MINGW: }
-# MINGW: }
-# MINGW: ]
+# BUILDID: File: {{.*}}.dll
+# BUILDID: DebugDirectory [
+# BUILDID: DebugEntry {
+# BUILDID: Characteristics: 0x0
+# BUILDID: TimeDateStamp:
+# BUILDID: MajorVersion: 0x0
+# BUILDID: MinorVersion: 0x0
+# BUILDID: Type: CodeView (0x2)
+# BUILDID: SizeOfData: 0x{{[^0]}}
+# BUILDID: AddressOfRawData: 0x{{[^0]}}
+# BUILDID: PointerToRawData: 0x{{[^0]}}
+# BUILDID: PDBInfo {
+# BUILDID: PDBSignature: 0x53445352
+# BUILDID: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
+# BUILDID: PDBAge: 1
+# BUILDID: PDBFileName:
+# BUILDID: }
+# BUILDID: }
+# BUILDID: ]
+
+# NO_BUILDID: DebugDirectory [
+# NO_BUILDID-NEXT: ]
+
+# BUILDID_SEC: Name: .buildid
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_I386
diff --git a/lld/test/MinGW/driver.test b/lld/test/MinGW/driver.test
index a07c95edb580d..d08c64258be89 100644
--- a/lld/test/MinGW/driver.test
+++ b/lld/test/MinGW/driver.test
@@ -389,3 +389,16 @@ Test GCC specific LTO options that GCC passes unconditionally, that we ignore.
RUN: ld.lld -### foo.o -m i386pep -plugin /usr/lib/gcc/x86_64-w64-mingw32/10-posix/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-w64-mingw32/10-posix/lto-wrapper -plugin-opt=-fresolution=/tmp/ccM9d4fP.res -plugin-opt=-pass-through=-lmingw32 2> /dev/null
RUN: ld.lld -### foo.o -m i386pep -plugin C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/liblto_plugin.dll -plugin-opt=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/lto-wrapper.exe -plugin-opt=-fresolution=C:/msys64/tmp/cckbC7wB.res -plugin-opt=-pass-through=-lmingw32 2> /dev/null
+
+RUN: ld.lld -### foo.o -m i386pep 2>&1 | FileCheck -check-prefix=BUILD_ID %s
+RUN: ld.lld -### foo.o -m i386pep --build-id 2>&1 | FileCheck -check-prefix=BUILD_ID %s
+BUILD_ID: -build-id{{ }}
+
+RUN: ld.lld -### foo.o -m i386pep --build-id=fast 2>&1 | FileCheck -check-prefix=BUILD_ID_WARN %s
+BUILD_ID_WARN: unsupported build id hashing: fast, using default hashing.
+BUILD_ID_WARN: -build-id{{ }}
+
+RUN: ld.lld -### foo.o -m i386pep --build-id=none 2>&1 | FileCheck -check-prefix=NO_BUILD_ID %s
+RUN: ld.lld -### foo.o -m i386pep -s 2>&1 | FileCheck -check-prefix=NO_BUILD_ID %s
+RUN: ld.lld -### foo.o -m i386pep -S 2>&1 | FileCheck -check-prefix=NO_BUILD_ID %s
+NO_BUILD_ID: -build-id:no
More information about the llvm-commits
mailing list