[lld] [lld][macho] Support order cstrings with -order_file (PR #140307)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 3 11:08:18 PDT 2025
https://github.com/SharonXSharon updated https://github.com/llvm/llvm-project/pull/140307
>From 4d0a7358771e3fe0009c7a2fcfb7e0a5c9bb86f4 Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Thu, 15 May 2025 15:44:13 -0700
Subject: [PATCH 1/6] [lld] Support order cstrings with -order_file_cstring
---
lld/MachO/Config.h | 1 +
lld/MachO/Driver.cpp | 21 +--
lld/MachO/Options.td | 4 +
lld/MachO/SectionPriorities.cpp | 71 +++++++++
lld/MachO/SectionPriorities.h | 20 +++
lld/MachO/SyntheticSections.cpp | 58 ++++----
lld/test/MachO/ordre-file-cstring.s | 222 ++++++++++++++++++++++++++++
7 files changed, 359 insertions(+), 38 deletions(-)
create mode 100644 lld/test/MachO/ordre-file-cstring.s
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index a01e60efbe761..d0217b38c3007 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -225,6 +225,7 @@ struct Configuration {
bool callGraphProfileSort = false;
llvm::StringRef printSymbolOrder;
+ llvm::StringRef cStringOrderFilePath;
llvm::StringRef irpgoProfilePath;
bool bpStartupFunctionSort = false;
bool bpCompressionSortStartupFunctions = false;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 5c32055166da6..0f2957295d136 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -337,15 +337,15 @@ static InputFile *addFile(StringRef path, LoadType loadType,
for (const object::Archive::Child &c : file->getArchive().children(e)) {
StringRef reason;
switch (loadType) {
- case LoadType::LCLinkerOption:
- reason = "LC_LINKER_OPTION";
- break;
- case LoadType::CommandLineForce:
- reason = "-force_load";
- break;
- case LoadType::CommandLine:
- reason = "-all_load";
- break;
+ case LoadType::LCLinkerOption:
+ reason = "LC_LINKER_OPTION";
+ break;
+ case LoadType::CommandLineForce:
+ reason = "-force_load";
+ break;
+ case LoadType::CommandLine:
+ reason = "-all_load";
+ break;
}
if (Error e = file->fetch(c, reason)) {
if (config->warnThinArchiveMissingMembers)
@@ -2178,6 +2178,9 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
StringRef orderFile = args.getLastArgValue(OPT_order_file);
if (!orderFile.empty())
priorityBuilder.parseOrderFile(orderFile);
+ config->cStringOrderFilePath = args.getLastArgValue(OPT_order_file_cstring);
+ if (!config->cStringOrderFilePath.empty())
+ priorityBuilder.parseOrderFileCString(config->cStringOrderFilePath);
referenceStubBinder();
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 4f0602f59812b..34faa75103224 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -400,6 +400,10 @@ def order_file : Separate<["-"], "order_file">,
MetaVarName<"<file>">,
HelpText<"Layout functions and data according to specification in <file>">,
Group<grp_opts>;
+def order_file_cstring : Separate<["-"], "order_file_cstring">,
+ MetaVarName<"<file>">,
+ HelpText<"Layout cstrings according to specification in <file>">,
+ Group<grp_opts>;
def no_order_inits : Flag<["-"], "no_order_inits">,
HelpText<"Disable default reordering of initializer and terminator functions">,
Flags<[HelpHidden]>,
diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp
index 7a4a5d8465f64..e7372050b7601 100644
--- a/lld/MachO/SectionPriorities.cpp
+++ b/lld/MachO/SectionPriorities.cpp
@@ -388,3 +388,74 @@ macho::PriorityBuilder::buildInputSectionPriorities() {
return sectionPriorities;
}
+
+void macho::PriorityBuilder::parseOrderFileCString(StringRef path) {
+ std::optional<MemoryBufferRef> buffer = readFile(path);
+ if (!buffer) {
+ error("Could not read cstring order file at " + path);
+ return;
+ }
+ MemoryBufferRef mbref = *buffer;
+ int priority = std::numeric_limits<int>::min();
+ for (StringRef line : args::getLines(mbref)) {
+ if (line.empty())
+ continue;
+ uint32_t hash = 0;
+ if (!to_integer(line, hash))
+ continue;
+ auto it = cStringPriorities.find(hash);
+ if (it == cStringPriorities.end())
+ cStringPriorities[hash] = ++priority;
+ else
+ assert(it->second <= priority);
+ }
+}
+
+std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities(
+ ArrayRef<CStringInputSection *> inputs) {
+ std::vector<StringPiecePair> orderedStringPieces;
+ if (config->cStringOrderFilePath.empty()) {
+ for (CStringInputSection *isec : inputs) {
+ for (const auto &[stringPieceIdx, piece] :
+ llvm::enumerate(isec->pieces)) {
+ if (!piece.live)
+ continue;
+ orderedStringPieces.emplace_back(isec, stringPieceIdx);
+ }
+ }
+ return orderedStringPieces;
+ }
+
+ // Split the input strings into hold and cold sets.
+ // Order hot set based on -order_file_cstring for performance improvement;
+ // TODO: Order cold set of cstrings for compression via BP.
+ std::vector<std::pair<int, StringPiecePair>>
+ hotStringPrioritiesAndStringPieces;
+ std::vector<StringPiecePair> coldStringPieces;
+
+ for (CStringInputSection *isec : inputs) {
+ for (const auto &[stringPieceIdx, piece] : llvm::enumerate(isec->pieces)) {
+ if (!piece.live)
+ continue;
+
+ auto it = cStringPriorities.find(piece.hash);
+ if (it != cStringPriorities.end())
+ hotStringPrioritiesAndStringPieces.emplace_back(
+ it->second, std::make_pair(isec, stringPieceIdx));
+ else
+ coldStringPieces.emplace_back(isec, stringPieceIdx);
+ }
+ }
+
+ // Order hot set for perf
+ llvm::stable_sort(hotStringPrioritiesAndStringPieces);
+ for (auto &[priority, stringPiecePair] : hotStringPrioritiesAndStringPieces)
+ orderedStringPieces.push_back(stringPiecePair);
+
+ // TODO: Order cold set for compression
+
+ orderedStringPieces.insert(orderedStringPieces.end(),
+ coldStringPieces.begin(), coldStringPieces.end());
+
+ return orderedStringPieces;
+}
diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h
index 44fb101990c51..5593494d8a274 100644
--- a/lld/MachO/SectionPriorities.h
+++ b/lld/MachO/SectionPriorities.h
@@ -16,6 +16,7 @@
namespace lld::macho {
using SectionPair = std::pair<const InputSection *, const InputSection *>;
+using StringPiecePair = std::pair<CStringInputSection *, size_t>;
class PriorityBuilder {
public:
@@ -55,6 +56,23 @@ class PriorityBuilder {
// contains.
llvm::DenseMap<const InputSection *, int> buildInputSectionPriorities();
+ // Reads the cstring order file at `path` into cStringPriorities.
+ // An cstring order file has one entry per line, in the following format:
+ //
+ // <hash of cstring literal content>
+ //
+ // Cstring literals are not symbolized, we can't identify them by name
+ // However, cstrings are deduplicated, hence unique, so we use the hash of
+ // the content of cstring literals to identify them and assign priority to it.
+ // We use the same hash as used in StringPiece, i.e. 31 bit:
+ // xxh3_64bits(string) & 0x7fffffff
+ //
+ // Additionally, given they are deduplicated and unique, we don't need to know
+ // which object file they are from.
+ void parseOrderFileCString(StringRef path);
+ std::vector<StringPiecePair>
+ buildCStringPriorities(ArrayRef<CStringInputSection *>);
+
private:
// The symbol with the smallest priority should be ordered first in the output
// section (modulo input section contiguity constraints).
@@ -68,6 +86,8 @@ class PriorityBuilder {
std::optional<int> getSymbolPriority(const Defined *sym);
llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
+ /// A map from cstring literal hashes to priorities
+ llvm::DenseMap<uint32_t, int> cStringPriorities;
llvm::MapVector<SectionPair, uint64_t> callGraphProfile;
};
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index dfacaf2ef4e0d..beddcfa2174e0 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -15,6 +15,7 @@
#include "MachOStructs.h"
#include "ObjC.h"
#include "OutputSegment.h"
+#include "SectionPriorities.h"
#include "SymbolTable.h"
#include "Symbols.h"
@@ -1766,26 +1767,25 @@ void DeduplicatedCStringSection::finalizeContents() {
}
}
- // Assign an offset for each string and save it to the corresponding
+ // Sort the strings for performance and compression size win, and then
+ // assign an offset for each string and save it to the corresponding
// StringPieces for easy access.
- for (CStringInputSection *isec : inputs) {
- for (const auto &[i, piece] : llvm::enumerate(isec->pieces)) {
- if (!piece.live)
- continue;
- auto s = isec->getCachedHashStringRef(i);
- auto it = stringOffsetMap.find(s);
- assert(it != stringOffsetMap.end());
- StringOffset &offsetInfo = it->second;
- if (offsetInfo.outSecOff == UINT64_MAX) {
- offsetInfo.outSecOff =
- alignToPowerOf2(size, 1ULL << offsetInfo.trailingZeros);
- size =
- offsetInfo.outSecOff + s.size() + 1; // account for null terminator
- }
- piece.outSecOff = offsetInfo.outSecOff;
+ for (auto &[isec, i] : priorityBuilder.buildCStringPriorities(inputs)) {
+ auto &piece = isec->pieces[i];
+ auto s = isec->getCachedHashStringRef(i);
+ auto it = stringOffsetMap.find(s);
+ assert(it != stringOffsetMap.end());
+ lld::macho::DeduplicatedCStringSection::StringOffset &offsetInfo =
+ it->second;
+ if (offsetInfo.outSecOff == UINT64_MAX) {
+ offsetInfo.outSecOff =
+ alignToPowerOf2(size, 1ULL << offsetInfo.trailingZeros);
+ size = offsetInfo.outSecOff + s.size() + 1; // account for null terminator
}
- isec->isFinal = true;
+ piece.outSecOff = offsetInfo.outSecOff;
}
+ for (CStringInputSection *isec : inputs)
+ isec->isFinal = true;
}
void DeduplicatedCStringSection::writeTo(uint8_t *buf) const {
@@ -1908,18 +1908,18 @@ ObjCImageInfoSection::parseImageInfo(const InputFile *file) {
static std::string swiftVersionString(uint8_t version) {
switch (version) {
- case 1:
- return "1.0";
- case 2:
- return "1.1";
- case 3:
- return "2.0";
- case 4:
- return "3.0";
- case 5:
- return "4.0";
- default:
- return ("0x" + Twine::utohexstr(version)).str();
+ case 1:
+ return "1.0";
+ case 2:
+ return "1.1";
+ case 3:
+ return "2.0";
+ case 4:
+ return "3.0";
+ case 5:
+ return "4.0";
+ default:
+ return ("0x" + Twine::utohexstr(version)).str();
}
}
diff --git a/lld/test/MachO/ordre-file-cstring.s b/lld/test/MachO/ordre-file-cstring.s
new file mode 100644
index 0000000000000..138f1685467ee
--- /dev/null
+++ b/lld/test/MachO/ordre-file-cstring.s
@@ -0,0 +1,222 @@
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/test.s -o %t/test.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/more-cstrings.s -o %t/more-cstrings.o
+
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-0 %t/test.o %t/more-cstrings.o
+# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-0 | FileCheck %s --check-prefix=ORIGIN_SYM
+# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-0 | FileCheck %s --check-prefix=ORIGIN_SEC
+
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-1 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-1
+# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-1 | FileCheck %s --check-prefix=ONE_SYM
+# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-1 | FileCheck %s --check-prefix=ONE_SEC
+
+
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-2 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-2
+# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-2 | FileCheck %s --check-prefix=TWO_SYM
+# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-2 | FileCheck %s --check-prefix=TWO_SEC
+
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-3 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-3
+# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-3 | FileCheck %s --check-prefix=THREE_SYM
+# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-3 | FileCheck %s --check-prefix=THREE_SEC
+
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-4 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-4
+# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-4 | FileCheck %s --check-prefix=FOUR_SYM
+# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-4 | FileCheck %s --check-prefix=FOUR_SEC
+# RUN: llvm-readobj --string-dump=__cstring %t/test-4 | FileCheck %s --check-prefix=FOUR_SEC_ESCAPE
+
+
+# We expect:
+# 1) Covered cstring symbols are reordered
+# 2) the rest of the cstring symbols remain original relative order within the cstring section
+
+# ORIGIN_SYM: _local_foo1
+# ORIGIN_SYM: _globl_foo2
+# ORIGIN_SYM: _local_foo2
+# ORIGIN_SYM: _bar
+# ORIGIN_SYM: _baz
+# ORIGIN_SYM: _baz_dup
+# ORIGIN_SYM: _bar2
+# ORIGIN_SYM: _globl_foo3
+
+# ORIGIN_SEC: foo1
+# ORIGIN_SEC: foo2
+# ORIGIN_SEC: bar
+# ORIGIN_SEC: baz
+# ORIGIN_SEC: bar2
+# ORIGIN_SEC: foo3
+
+
+# ONE_SYM: _globl_foo2
+# ONE_SYM: _local_foo2
+# ONE_SYM: _bar
+# ONE_SYM: _bar2
+# ONE_SYM: _globl_foo3
+# ONE_SYM: _local_foo1
+# ONE_SYM: _baz
+# ONE_SYM: _baz_dup
+
+# ONE_SEC: foo2
+# ONE_SEC: bar
+# ONE_SEC: bar2
+# ONE_SEC: foo3
+# ONE_SEC: foo1
+# ONE_SEC: baz
+
+
+# TWO_SYM: _globl_foo2
+# TWO_SYM: _local_foo2
+# TWO_SYM: _local_foo1
+# TWO_SYM: _baz
+# TWO_SYM: _baz_dup
+# TWO_SYM: _bar
+# TWO_SYM: _bar2
+# TWO_SYM: _globl_foo3
+
+# TWO_SEC: foo2
+# TWO_SEC: foo1
+# TWO_SEC: baz
+# TWO_SEC: bar
+# TWO_SEC: bar2
+# TWO_SEC: foo3
+
+
+# THREE_SYM: _local_foo1
+# THREE_SYM: _baz
+# THREE_SYM: _baz_dup
+# THREE_SYM: _bar
+# THREE_SYM: _bar2
+# THREE_SYM: _globl_foo2
+# THREE_SYM: _local_foo2
+# THREE_SYM: _globl_foo3
+
+# THREE_SEC: foo1
+# THREE_SEC: baz
+# THREE_SEC: bar
+# THREE_SEC: bar2
+# THREE_SEC: foo2
+# THREE_SEC: foo3
+
+
+# FOUR_SYM: _local_escape_white_space
+# FOUR_SYM: _globl_foo2
+# FOUR_SYM: _local_foo2
+# FOUR_SYM: _local_escape
+# FOUR_SYM: _globl_foo3
+# FOUR_SYM: _bar
+# FOUR_SYM: _local_foo1
+# FOUR_SYM: _baz
+# FOUR_SYM: _baz_dup
+# FOUR_SYM: _bar2
+
+# FOUR_SEC: \t\n
+# FOUR_SEC: foo2
+# FOUR_SEC: @\"NSDictionary\"
+# FOUR_SEC: foo3
+# FOUR_SEC: bar
+# FOUR_SEC: foo1
+# FOUR_SEC: baz
+# FOUR_SEC: bar2
+
+# FOUR_SEC_ESCAPE: ..
+# FOUR_SEC_ESCAPE: foo2
+# FOUR_SEC_ESCAPE: @"NSDictionary"
+# FOUR_SEC_ESCAPE: foo3
+# FOUR_SEC_ESCAPE: bar
+# FOUR_SEC_ESCAPE: foo1
+# FOUR_SEC_ESCAPE: baz
+# FOUR_SEC_ESCAPE: bar2
+
+# original order, but only parital covered
+#--- ord-1
+#foo2
+0x55783A95
+#bar
+0x2032D362
+#bar2
+0x592F855B
+#foo3
+0x501BCC31
+
+# change order, parital covered
+#--- ord-2
+#foo2
+0x55783A95
+#foo1
+0x6326A039
+#baz
+0x336F8925
+#bar
+0x2032D362
+#bar2
+0x592F855B
+
+# change order, parital covered, with mismatches, duplicates
+#--- ord-3
+foo2222
+0x11111111
+#foo1
+0x6326A039
+#baz
+0x336F8925
+#bar
+0x2032D362
+#bar2
+0x592F855B
+#baz
+0x336F8925
+
+# test escape strings
+#--- ord-4
+#\t\n
+0x3DBEA0C9
+#foo2
+0x55783A95
+#@\"NSDictionary\"
+0x47AF4776
+#foo3
+0x501BCC31
+#bar
+0x2032D362
+
+
+#--- test.s
+.text
+.globl _main
+
+_main:
+ ret
+
+.cstring
+.p2align 2
+_local_foo1:
+ .asciz "foo1"
+_local_foo2:
+ .asciz "foo2"
+L_.foo1_dup:
+ .asciz "foo1"
+L_.foo2_dup:
+ .asciz "foo2"
+_local_escape:
+ .asciz "@\"NSDictionary\""
+_local_escape_white_space:
+ .asciz "\t\n"
+
+_bar:
+ .asciz "bar"
+_baz:
+ .asciz "baz"
+_bar2:
+ .asciz "bar2"
+_baz_dup:
+ .asciz "baz"
+
+.subsections_via_symbols
+
+#--- more-cstrings.s
+.globl _globl_foo1, _globl_foo3
+.cstring
+.p2align 4
+_globl_foo3:
+ .asciz "foo3"
+_globl_foo2:
+ .asciz "foo2"
>From 9d251c4e0d82eff273257d1e98a7b0eb3b56f5a7 Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Mon, 19 May 2025 11:42:51 -0700
Subject: [PATCH 2/6] address comments
---
lld/MachO/Driver.cpp | 18 +++++++++---------
lld/MachO/SectionPriorities.cpp | 22 ++++------------------
lld/MachO/SyntheticSections.cpp | 24 ++++++++++++------------
3 files changed, 25 insertions(+), 39 deletions(-)
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 0f2957295d136..d071202bd1b46 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -337,15 +337,15 @@ static InputFile *addFile(StringRef path, LoadType loadType,
for (const object::Archive::Child &c : file->getArchive().children(e)) {
StringRef reason;
switch (loadType) {
- case LoadType::LCLinkerOption:
- reason = "LC_LINKER_OPTION";
- break;
- case LoadType::CommandLineForce:
- reason = "-force_load";
- break;
- case LoadType::CommandLine:
- reason = "-all_load";
- break;
+ case LoadType::LCLinkerOption:
+ reason = "LC_LINKER_OPTION";
+ break;
+ case LoadType::CommandLineForce:
+ reason = "-force_load";
+ break;
+ case LoadType::CommandLine:
+ reason = "-all_load";
+ break;
}
if (Error e = file->fetch(c, reason)) {
if (config->warnThinArchiveMissingMembers)
diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp
index e7372050b7601..0f311739c862e 100644
--- a/lld/MachO/SectionPriorities.cpp
+++ b/lld/MachO/SectionPriorities.cpp
@@ -403,35 +403,21 @@ void macho::PriorityBuilder::parseOrderFileCString(StringRef path) {
uint32_t hash = 0;
if (!to_integer(line, hash))
continue;
- auto it = cStringPriorities.find(hash);
- if (it == cStringPriorities.end())
- cStringPriorities[hash] = ++priority;
- else
- assert(it->second <= priority);
+ auto [it, wasInserted] = cStringPriorities.try_emplace(hash, priority);
+ if (wasInserted)
+ ++priority;
}
}
std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities(
ArrayRef<CStringInputSection *> inputs) {
- std::vector<StringPiecePair> orderedStringPieces;
- if (config->cStringOrderFilePath.empty()) {
- for (CStringInputSection *isec : inputs) {
- for (const auto &[stringPieceIdx, piece] :
- llvm::enumerate(isec->pieces)) {
- if (!piece.live)
- continue;
- orderedStringPieces.emplace_back(isec, stringPieceIdx);
- }
- }
- return orderedStringPieces;
- }
-
// Split the input strings into hold and cold sets.
// Order hot set based on -order_file_cstring for performance improvement;
// TODO: Order cold set of cstrings for compression via BP.
std::vector<std::pair<int, StringPiecePair>>
hotStringPrioritiesAndStringPieces;
std::vector<StringPiecePair> coldStringPieces;
+ std::vector<StringPiecePair> orderedStringPieces;
for (CStringInputSection *isec : inputs) {
for (const auto &[stringPieceIdx, piece] : llvm::enumerate(isec->pieces)) {
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index beddcfa2174e0..806858a961b99 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -1908,18 +1908,18 @@ ObjCImageInfoSection::parseImageInfo(const InputFile *file) {
static std::string swiftVersionString(uint8_t version) {
switch (version) {
- case 1:
- return "1.0";
- case 2:
- return "1.1";
- case 3:
- return "2.0";
- case 4:
- return "3.0";
- case 5:
- return "4.0";
- default:
- return ("0x" + Twine::utohexstr(version)).str();
+ case 1:
+ return "1.0";
+ case 2:
+ return "1.1";
+ case 3:
+ return "2.0";
+ case 4:
+ return "3.0";
+ case 5:
+ return "4.0";
+ default:
+ return ("0x" + Twine::utohexstr(version)).str();
}
}
>From f39f9084ba6029f976a2e2012015c95af45d23ae Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Thu, 22 May 2025 17:00:51 -0700
Subject: [PATCH 3/6] use -order_file for cstring hashes
---
lld/MachO/Config.h | 1 -
lld/MachO/Driver.cpp | 21 ++++-----
lld/MachO/Options.td | 4 --
lld/MachO/SectionPriorities.cpp | 68 ++++++++++++++---------------
lld/MachO/SectionPriorities.h | 42 ++++++++----------
lld/test/MachO/ordre-file-cstring.s | 64 ++++++++++++++-------------
6 files changed, 95 insertions(+), 105 deletions(-)
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index d0217b38c3007..a01e60efbe761 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -225,7 +225,6 @@ struct Configuration {
bool callGraphProfileSort = false;
llvm::StringRef printSymbolOrder;
- llvm::StringRef cStringOrderFilePath;
llvm::StringRef irpgoProfilePath;
bool bpStartupFunctionSort = false;
bool bpCompressionSortStartupFunctions = false;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index d071202bd1b46..0b9c32f047f27 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -337,15 +337,15 @@ static InputFile *addFile(StringRef path, LoadType loadType,
for (const object::Archive::Child &c : file->getArchive().children(e)) {
StringRef reason;
switch (loadType) {
- case LoadType::LCLinkerOption:
- reason = "LC_LINKER_OPTION";
- break;
- case LoadType::CommandLineForce:
- reason = "-force_load";
- break;
- case LoadType::CommandLine:
- reason = "-all_load";
- break;
+ case LoadType::LCLinkerOption:
+ reason = "LC_LINKER_OPTION";
+ break;
+ case LoadType::CommandLineForce:
+ reason = "-force_load";
+ break;
+ case LoadType::CommandLine:
+ reason = "-all_load";
+ break;
}
if (Error e = file->fetch(c, reason)) {
if (config->warnThinArchiveMissingMembers)
@@ -2178,9 +2178,6 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
StringRef orderFile = args.getLastArgValue(OPT_order_file);
if (!orderFile.empty())
priorityBuilder.parseOrderFile(orderFile);
- config->cStringOrderFilePath = args.getLastArgValue(OPT_order_file_cstring);
- if (!config->cStringOrderFilePath.empty())
- priorityBuilder.parseOrderFileCString(config->cStringOrderFilePath);
referenceStubBinder();
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 34faa75103224..4f0602f59812b 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -400,10 +400,6 @@ def order_file : Separate<["-"], "order_file">,
MetaVarName<"<file>">,
HelpText<"Layout functions and data according to specification in <file>">,
Group<grp_opts>;
-def order_file_cstring : Separate<["-"], "order_file_cstring">,
- MetaVarName<"<file>">,
- HelpText<"Layout cstrings according to specification in <file>">,
- Group<grp_opts>;
def no_order_inits : Flag<["-"], "no_order_inits">,
HelpText<"Disable default reordering of initializer and terminator functions">,
Flags<[HelpHidden]>,
diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp
index 0f311739c862e..1424b234d7153 100644
--- a/lld/MachO/SectionPriorities.cpp
+++ b/lld/MachO/SectionPriorities.cpp
@@ -246,15 +246,15 @@ DenseMap<const InputSection *, int> CallGraphSort::run() {
}
std::optional<int>
-macho::PriorityBuilder::getSymbolPriority(const Defined *sym) {
- if (sym->isAbsolute())
- return std::nullopt;
+macho::PriorityBuilder::getSymbolOrCStringPriority(const StringRef key,
+ InputFile *f) {
- auto it = priorities.find(sym->getName());
+ for (auto &[name, entry] : priorities)
+ llvm::errs() << name << ", " << entry.anyObjectFile << "\n";
+ auto it = priorities.find(key);
if (it == priorities.end())
return std::nullopt;
const SymbolPriorityEntry &entry = it->second;
- const InputFile *f = sym->isec()->getFile();
if (!f)
return entry.anyObjectFile;
// We don't use toString(InputFile *) here because it returns the full path
@@ -268,6 +268,13 @@ macho::PriorityBuilder::getSymbolPriority(const Defined *sym) {
return std::min(entry.objectFiles.lookup(filename), entry.anyObjectFile);
}
+std::optional<int>
+macho::PriorityBuilder::getSymbolPriority(const Defined *sym) {
+ if (sym->isAbsolute())
+ return std::nullopt;
+ return getSymbolOrCStringPriority(sym->getName(), sym->isec()->getFile());
+}
+
void macho::PriorityBuilder::extractCallGraphProfile() {
TimeTraceScope timeScope("Extract call graph profile");
bool hasOrderFile = !priorities.empty();
@@ -300,7 +307,7 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) {
int prio = std::numeric_limits<int>::min();
MemoryBufferRef mbref = *buffer;
for (StringRef line : args::getLines(mbref)) {
- StringRef objectFile, symbol;
+ StringRef objectFile, symbolOrCStrHash;
line = line.take_until([](char c) { return c == '#'; }); // ignore comments
line = line.ltrim();
@@ -315,7 +322,6 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) {
if (cpuType != CPU_TYPE_ANY && cpuType != target->cpuType)
continue;
-
// Drop the CPU type as well as the colon
if (cpuType != CPU_TYPE_ANY)
line = line.drop_until([](char c) { return c == ':'; }).drop_front();
@@ -330,10 +336,20 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) {
break;
}
}
- symbol = line.trim();
- if (!symbol.empty()) {
- SymbolPriorityEntry &entry = priorities[symbol];
+ // The rest of the line is either <symbol name> or
+ // CStringEntryPrefix<cstring hash>
+ if (line.starts_with(CStringEntryPrefix)) {
+ StringRef possibleHash = line.drop_front(CStringEntryPrefix.size());
+ uint32_t hash = 0;
+ if (to_integer(possibleHash, hash))
+ line = possibleHash;
+ }
+ symbolOrCStrHash = line.trim();
+ llvm::errs() << symbolOrCStrHash << "\n";
+
+ if (!symbolOrCStrHash.empty()) {
+ SymbolPriorityEntry &entry = priorities[symbolOrCStrHash];
if (!objectFile.empty())
entry.objectFiles.insert(std::make_pair(objectFile, prio));
else
@@ -389,26 +405,6 @@ macho::PriorityBuilder::buildInputSectionPriorities() {
return sectionPriorities;
}
-void macho::PriorityBuilder::parseOrderFileCString(StringRef path) {
- std::optional<MemoryBufferRef> buffer = readFile(path);
- if (!buffer) {
- error("Could not read cstring order file at " + path);
- return;
- }
- MemoryBufferRef mbref = *buffer;
- int priority = std::numeric_limits<int>::min();
- for (StringRef line : args::getLines(mbref)) {
- if (line.empty())
- continue;
- uint32_t hash = 0;
- if (!to_integer(line, hash))
- continue;
- auto [it, wasInserted] = cStringPriorities.try_emplace(hash, priority);
- if (wasInserted)
- ++priority;
- }
-}
-
std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities(
ArrayRef<CStringInputSection *> inputs) {
// Split the input strings into hold and cold sets.
@@ -424,12 +420,14 @@ std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities(
if (!piece.live)
continue;
- auto it = cStringPriorities.find(piece.hash);
- if (it != cStringPriorities.end())
- hotStringPrioritiesAndStringPieces.emplace_back(
- it->second, std::make_pair(isec, stringPieceIdx));
- else
+ llvm::errs() << "buildCStringPriorities:" << piece.hash << "\n";
+ std::optional<int> priority = getSymbolOrCStringPriority(
+ std::to_string(piece.hash), isec->getFile());
+ if (!priority)
coldStringPieces.emplace_back(isec, stringPieceIdx);
+ else
+ hotStringPrioritiesAndStringPieces.emplace_back(
+ *priority, std::make_pair(isec, stringPieceIdx));
}
}
diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h
index 5593494d8a274..96c8f0b34bfc1 100644
--- a/lld/MachO/SectionPriorities.h
+++ b/lld/MachO/SectionPriorities.h
@@ -29,17 +29,28 @@ class PriorityBuilder {
//
// An order file has one entry per line, in the following format:
//
- // <cpu>:<object file>:<symbol name>
+ // <cpu>:<object file>:[<symbol name> | CStringEntryPrefix <cstring hash>]
//
- // <cpu> and <object file> are optional. If not specified, then that entry
- // matches any symbol of that name. Parsing this format is not quite
- // straightforward because the symbol name itself can contain colons, so when
- // encountering a colon, we consider the preceding characters to decide if it
- // can be a valid CPU type or file path.
+ // <cpu> and <object file> are optional.
+ // If not specified, then that entry tries to match either,
//
+ // 1) any symbol of the <symbol name>;
+ // Parsing this format is not quite straightforward because the symbol name
+ // itself can contain colons, so when encountering a colon, we consider the
+ // preceding characters to decide if it can be a valid CPU type or file path.
// If a symbol is matched by multiple entries, then it takes the
// lowest-ordered entry (the one nearest to the front of the list.)
//
+ // or 2) any cstring literal with the given hash, if the entry has the
+ // CStringEntryPrefix prefix defined below in the file. <cstring hash> is the
+ // hash of cstring literal content.
+ //
+ // Cstring literals are not symbolized, we can't identify them by name
+ // However, cstrings are deduplicated, hence unique, so we use the hash of
+ // the content of cstring literals to identify them and assign priority to it.
+ // We use the same hash as used in StringPiece, i.e. 31 bit:
+ // xxh3_64bits(string) & 0x7fffffff
+ //
// The file can also have line comments that start with '#'.
void parseOrderFile(StringRef path);
@@ -55,21 +66,6 @@ class PriorityBuilder {
// Each section gets assigned the priority of the highest-priority symbol it
// contains.
llvm::DenseMap<const InputSection *, int> buildInputSectionPriorities();
-
- // Reads the cstring order file at `path` into cStringPriorities.
- // An cstring order file has one entry per line, in the following format:
- //
- // <hash of cstring literal content>
- //
- // Cstring literals are not symbolized, we can't identify them by name
- // However, cstrings are deduplicated, hence unique, so we use the hash of
- // the content of cstring literals to identify them and assign priority to it.
- // We use the same hash as used in StringPiece, i.e. 31 bit:
- // xxh3_64bits(string) & 0x7fffffff
- //
- // Additionally, given they are deduplicated and unique, we don't need to know
- // which object file they are from.
- void parseOrderFileCString(StringRef path);
std::vector<StringPiecePair>
buildCStringPriorities(ArrayRef<CStringInputSection *>);
@@ -83,11 +79,11 @@ class PriorityBuilder {
// The priority given to a matching symbol from a particular object file.
llvm::DenseMap<llvm::StringRef, int> objectFiles;
};
+ const llvm::StringRef CStringEntryPrefix = "CSTR:";
std::optional<int> getSymbolPriority(const Defined *sym);
+ std::optional<int> getSymbolOrCStringPriority(const StringRef key, InputFile *f);
llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
- /// A map from cstring literal hashes to priorities
- llvm::DenseMap<uint32_t, int> cStringPriorities;
llvm::MapVector<SectionPair, uint64_t> callGraphProfile;
};
diff --git a/lld/test/MachO/ordre-file-cstring.s b/lld/test/MachO/ordre-file-cstring.s
index 138f1685467ee..fac2758dcc804 100644
--- a/lld/test/MachO/ordre-file-cstring.s
+++ b/lld/test/MachO/ordre-file-cstring.s
@@ -6,20 +6,20 @@
# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-0 | FileCheck %s --check-prefix=ORIGIN_SYM
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-0 | FileCheck %s --check-prefix=ORIGIN_SEC
-# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-1 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-1
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-1 %t/test.o %t/more-cstrings.o -order_file %t/ord-1
# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-1 | FileCheck %s --check-prefix=ONE_SYM
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-1 | FileCheck %s --check-prefix=ONE_SEC
-# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-2 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-2
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-2 %t/test.o %t/more-cstrings.o -order_file %t/ord-2
# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-2 | FileCheck %s --check-prefix=TWO_SYM
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-2 | FileCheck %s --check-prefix=TWO_SEC
-# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-3 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-3
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-3 %t/test.o %t/more-cstrings.o -order_file %t/ord-3
# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-3 | FileCheck %s --check-prefix=THREE_SYM
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-3 | FileCheck %s --check-prefix=THREE_SEC
-# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-4 %t/test.o %t/more-cstrings.o -order_file_cstring %t/ord-4
+# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-4 %t/test.o %t/more-cstrings.o -order_file %t/ord-4
# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-4 | FileCheck %s --check-prefix=FOUR_SYM
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-4 | FileCheck %s --check-prefix=FOUR_SEC
# RUN: llvm-readobj --string-dump=__cstring %t/test-4 | FileCheck %s --check-prefix=FOUR_SEC_ESCAPE
@@ -45,6 +45,16 @@
# ORIGIN_SEC: bar2
# ORIGIN_SEC: foo3
+# original order, but only parital covered
+#--- ord-1
+#foo2
+CSTR:1433942677
+#bar
+CSTR:540201826
+#bar2
+CSTR:1496286555
+#foo3
+CSTR:1343999025
# ONE_SYM: _globl_foo2
# ONE_SYM: _local_foo2
@@ -126,57 +136,51 @@
# FOUR_SEC_ESCAPE: baz
# FOUR_SEC_ESCAPE: bar2
-# original order, but only parital covered
-#--- ord-1
-#foo2
-0x55783A95
-#bar
-0x2032D362
-#bar2
-0x592F855B
-#foo3
-0x501BCC31
# change order, parital covered
#--- ord-2
#foo2
-0x55783A95
+CSTR:1433942677
#foo1
-0x6326A039
+CSTR:1663475769
#baz
-0x336F8925
+CSTR:862947621
#bar
-0x2032D362
+CSTR:540201826
#bar2
-0x592F855B
+CSTR:1496286555
# change order, parital covered, with mismatches, duplicates
#--- ord-3
foo2222
-0x11111111
+CSTR:0x11111111
+#bar (mismatched cpu and file name)
+fakeCPU:fake-file-name.o:CSTR:540201826
+#not a hash
+CSTR:xxx
#foo1
-0x6326A039
+CSTR:1663475769
#baz
-0x336F8925
+CSTR:862947621
#bar
-0x2032D362
+CSTR:540201826
#bar2
-0x592F855B
+CSTR:1496286555
#baz
-0x336F8925
+CSTR:862947621
# test escape strings
#--- ord-4
#\t\n
-0x3DBEA0C9
+CSTR:1035903177
#foo2
-0x55783A95
+CSTR:1433942677
#@\"NSDictionary\"
-0x47AF4776
+CSTR:1202669430
#foo3
-0x501BCC31
+CSTR:1343999025
#bar
-0x2032D362
+CSTR:540201826
#--- test.s
>From 7c089997a32c70843377fe934abb0c3c729b37b1 Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Tue, 27 May 2025 18:37:43 -0700
Subject: [PATCH 4/6] fix typo
---
lld/MachO/Driver.cpp | 18 +++++++++---------
lld/MachO/SectionPriorities.cpp | 4 ----
2 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 0b9c32f047f27..5c32055166da6 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -337,15 +337,15 @@ static InputFile *addFile(StringRef path, LoadType loadType,
for (const object::Archive::Child &c : file->getArchive().children(e)) {
StringRef reason;
switch (loadType) {
- case LoadType::LCLinkerOption:
- reason = "LC_LINKER_OPTION";
- break;
- case LoadType::CommandLineForce:
- reason = "-force_load";
- break;
- case LoadType::CommandLine:
- reason = "-all_load";
- break;
+ case LoadType::LCLinkerOption:
+ reason = "LC_LINKER_OPTION";
+ break;
+ case LoadType::CommandLineForce:
+ reason = "-force_load";
+ break;
+ case LoadType::CommandLine:
+ reason = "-all_load";
+ break;
}
if (Error e = file->fetch(c, reason)) {
if (config->warnThinArchiveMissingMembers)
diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp
index 1424b234d7153..9c968eb01cfce 100644
--- a/lld/MachO/SectionPriorities.cpp
+++ b/lld/MachO/SectionPriorities.cpp
@@ -249,8 +249,6 @@ std::optional<int>
macho::PriorityBuilder::getSymbolOrCStringPriority(const StringRef key,
InputFile *f) {
- for (auto &[name, entry] : priorities)
- llvm::errs() << name << ", " << entry.anyObjectFile << "\n";
auto it = priorities.find(key);
if (it == priorities.end())
return std::nullopt;
@@ -346,7 +344,6 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) {
line = possibleHash;
}
symbolOrCStrHash = line.trim();
- llvm::errs() << symbolOrCStrHash << "\n";
if (!symbolOrCStrHash.empty()) {
SymbolPriorityEntry &entry = priorities[symbolOrCStrHash];
@@ -420,7 +417,6 @@ std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities(
if (!piece.live)
continue;
- llvm::errs() << "buildCStringPriorities:" << piece.hash << "\n";
std::optional<int> priority = getSymbolOrCStringPriority(
std::to_string(piece.hash), isec->getFile());
if (!priority)
>From b2c4acb510796771d8224d15744b933f63fd0571 Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Tue, 27 May 2025 18:39:34 -0700
Subject: [PATCH 5/6] fix typo2
---
lld/MachO/SectionPriorities.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h
index 96c8f0b34bfc1..85faa4aaf1fc3 100644
--- a/lld/MachO/SectionPriorities.h
+++ b/lld/MachO/SectionPriorities.h
@@ -82,7 +82,8 @@ class PriorityBuilder {
const llvm::StringRef CStringEntryPrefix = "CSTR:";
std::optional<int> getSymbolPriority(const Defined *sym);
- std::optional<int> getSymbolOrCStringPriority(const StringRef key, InputFile *f);
+ std::optional<int> getSymbolOrCStringPriority(const StringRef key,
+ InputFile *f);
llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
llvm::MapVector<SectionPair, uint64_t> callGraphProfile;
};
>From af0f01985bdd780c48d6f20bc4fcc4c90a194e08 Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Tue, 3 Jun 2025 09:51:02 -0700
Subject: [PATCH 6/6] fix the cstr prefix from CSTR: to CSTR;
---
lld/MachO/SectionPriorities.h | 2 +-
lld/test/MachO/ordre-file-cstring.s | 44 ++++++++++++++---------------
2 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h
index 85faa4aaf1fc3..cc4e30fffc600 100644
--- a/lld/MachO/SectionPriorities.h
+++ b/lld/MachO/SectionPriorities.h
@@ -79,7 +79,7 @@ class PriorityBuilder {
// The priority given to a matching symbol from a particular object file.
llvm::DenseMap<llvm::StringRef, int> objectFiles;
};
- const llvm::StringRef CStringEntryPrefix = "CSTR:";
+ const llvm::StringRef CStringEntryPrefix = "CSTR;";
std::optional<int> getSymbolPriority(const Defined *sym);
std::optional<int> getSymbolOrCStringPriority(const StringRef key,
diff --git a/lld/test/MachO/ordre-file-cstring.s b/lld/test/MachO/ordre-file-cstring.s
index fac2758dcc804..b5e3b01ce043a 100644
--- a/lld/test/MachO/ordre-file-cstring.s
+++ b/lld/test/MachO/ordre-file-cstring.s
@@ -48,13 +48,13 @@
# original order, but only parital covered
#--- ord-1
#foo2
-CSTR:1433942677
+CSTR;1433942677
#bar
-CSTR:540201826
+CSTR;540201826
#bar2
-CSTR:1496286555
+CSTR;1496286555
#foo3
-CSTR:1343999025
+CSTR;1343999025
# ONE_SYM: _globl_foo2
# ONE_SYM: _local_foo2
@@ -140,47 +140,47 @@ CSTR:1343999025
# change order, parital covered
#--- ord-2
#foo2
-CSTR:1433942677
+CSTR;1433942677
#foo1
-CSTR:1663475769
+CSTR;1663475769
#baz
-CSTR:862947621
+CSTR;862947621
#bar
-CSTR:540201826
+CSTR;540201826
#bar2
-CSTR:1496286555
+CSTR;1496286555
# change order, parital covered, with mismatches, duplicates
#--- ord-3
foo2222
-CSTR:0x11111111
+CSTR;0x11111111
#bar (mismatched cpu and file name)
-fakeCPU:fake-file-name.o:CSTR:540201826
+fakeCPU:fake-file-name.o:CSTR;540201826
#not a hash
-CSTR:xxx
+CSTR;xxx
#foo1
-CSTR:1663475769
+CSTR;1663475769
#baz
-CSTR:862947621
+CSTR;862947621
#bar
-CSTR:540201826
+CSTR;540201826
#bar2
-CSTR:1496286555
+CSTR;1496286555
#baz
-CSTR:862947621
+CSTR;862947621
# test escape strings
#--- ord-4
#\t\n
-CSTR:1035903177
+CSTR;1035903177
#foo2
-CSTR:1433942677
+CSTR;1433942677
#@\"NSDictionary\"
-CSTR:1202669430
+CSTR;1202669430
#foo3
-CSTR:1343999025
+CSTR;1343999025
#bar
-CSTR:540201826
+CSTR;540201826
#--- test.s
More information about the llvm-commits
mailing list