This is an archive of the discontinued LLVM Phabricator instance.

[lld-macho] Preserve alignment for non-deduplicated cstrings
ClosedPublic

Authored by lgrey on Jun 25 2021, 7:36 AM.

Details

Summary

Fixes PR50637

Downstream bug: https://crbug.com/1218958

Currently, we split __cstring along symbol boundaries with .subsections_via_symbols
when not deduplicating, and along null bytes when deduplicating. This change splits
along null bytes unconditionally, and preserves original alignment in the non-
deduplicated case.

Removing subsections-section-relocs.s because with this change, __cstring
is never reordered based on the order file. From offline conversation, thakis@
believes that the new test sufficiently exercises splitting.

Diff Detail

Event Timeline

lgrey created this revision.Jun 25 2021, 7:36 AM
Herald added a reviewer: gkm. · View Herald Transcript
Herald added a project: Restricted Project. · View Herald Transcript
lgrey requested review of this revision.Jun 25 2021, 7:36 AM
lgrey set the repository for this revision to rG LLVM Github Monorepo.Jun 25 2021, 7:37 AM
lgrey added a subscriber: llvm-commits.
Herald added a project: Restricted Project. · View Herald TranscriptJun 25 2021, 7:37 AM
thakis added a subscriber: thakis.Jun 25 2021, 8:23 AM

Nice!

Add "Fixes PR50637" to the commit message, since it fixes llvm.org/PR50637

I'd word the commit message as "__cstring is special in that it is split at null bytes instead of at symbol boundaries with .subsections_via_symbols" or something like that.

Please mention in the patch description why you're removing subsections-section-relocs.s.

lld/MachO/SyntheticSections.cpp
1191

I think that'd be nice. You just need

% git diff
diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h
index 3dd31d27be91..413b7aed70e7 100644
--- a/lld/MachO/InputSection.h
+++ b/lld/MachO/InputSection.h
@@ -183,11 +183,15 @@ public:
   // Returns i'th piece as a CachedHashStringRef. This function is very hot when
   // string merging is enabled, so we want to inline.
   LLVM_ATTRIBUTE_ALWAYS_INLINE
-  llvm::CachedHashStringRef getCachedHashStringRef(size_t i) const {
+  StringRef getStringRef(size_t i) const {
     size_t begin = pieces[i].inSecOff;
     size_t end =
         (pieces.size() - 1 == i) ? data.size() : pieces[i + 1].inSecOff;
-    return {toStringRef(data.slice(begin, end - begin)), pieces[i].hash};
+    return toStringRef(data.slice(begin, end - begin));
+  }
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
+  llvm::CachedHashStringRef getCachedHashStringRef(size_t i) const {
+    return {getStringRef(i), pieces[i].hash};
   }

   static bool classof(const InputSection *isec) {

and then you could call getStringRef() here, right?

lld/MachO/SyntheticSections.h
530

Maybe this should just be the default impl in CStringSection and DedupStringSection overrides it?

thakis added inline comments.Jun 25 2021, 8:25 AM
lld/MachO/SyntheticSections.cpp
1191

(and give splitIntoPieces() a toggle to control if it computes a hash or not.)

lgrey updated this revision to Diff 354536.Jun 25 2021, 10:57 AM
lgrey edited the summary of this revision. (Show Details)
  • Collapse class hierarchy so CStringSection handles the non dedup case
  • Make string hashing optional, and only do when deduping
  • Update commit message
lgrey marked an inline comment as done.Jun 25 2021, 10:58 AM
lgrey added inline comments.
lld/MachO/SyntheticSections.cpp
1191

Baked it into the implementation

thakis accepted this revision.Jun 25 2021, 11:31 AM

Oh, I didn't realize this breaks -order_file for strings. But I think it's fine to leave this for a follow-up. --deduplicate-strings already has that bug after all, and not creating crashing binaries is definitely better than not being able to reorder strings :)

lg. Let's wait a few hours to see if anyone else chimes in. If not, I'll land this for you.

(I kind of wish we could put make InputSection small and fast enough that we could just do one regular InputSection per string....)

This revision is now accepted and ready to land.Jun 25 2021, 11:31 AM
int3 added a comment.Jun 25 2021, 2:24 PM

Oh, I didn't realize this breaks -order_file for strings

I think it's fine actually -- in theory, cstrings can be reordered based on their literal values (instead of via symbol names) -- or at least that's what ld64's manpage suggests. In practice it doesn't actually seem to work. So we can probably come up with an alternative ordering mechanism for cstrings at some point

(I kind of wish we could put make InputSection small and fast enough that we could just do one regular InputSection per string....)

FWIW, I belatedly realized that my benchmarking diff D104159 (and the current StringPiece implementation) has a flaw: they create one InputSection/StringPiece respectively for every null byte, and since the Mach-O format employs zero padding extensively for alignment, we're actually allocating a bunch of useless stuff for zero-length strings. I guess this isn't an issue with ELF since it creates separate sections for strings that need to be aligned.

lld/test/MachO/dead-strip-align.s
2

needs a # REQUIRES: x86 line above

14

should we test for a non-zero offset as well?

21

this section header is redundant

26

ditto

I think it's fine actually -- in theory, cstrings can be reordered based on their literal values (instead of via symbol names) -- or at least that's what ld64's manpage suggests. In practice it doesn't actually seem to work.

Works for me:

thakis@MBP llvm-project % cat strings.cc
const char k1[] = "hi";
const char k2[] = "hallo";

extern "C" int puts(const char*);

int main() {
  puts(k1);
  puts(k2);
}
thakis@MBP llvm-project % clang strings.cc
thakis@MBP llvm-project % otool -s __TEXT __const a.out
a.out:
Contents of (__TEXT,__const) section
0000000100003fa2	68 69 00 68 61 6c 6c 6f 00
thakis@MBP llvm-project % clang strings.cc -Wl,-order_file,order.txt
thakis@MBP llvm-project % otool -s __TEXT __const a.out
a.out:
Contents of (__TEXT,__const) section
0000000100003fa2	68 61 6c 6c 6f 00 68 69 00
thakis@MBP llvm-project % cat order.txt
__ZL2k2
__ZL2k1
int3 added a comment.Jun 25 2021, 4:54 PM

Ah. I meant that an order file like

"hi"
"hallo"

Should work according to ld64's manpage (and its code), but doesn't seem to work in practice. Didn't think about the regular symbol case, I guess it might be worthwhile to find some way to make that still work. (Alternatively, maybe just supporting literal-value-based ordering will be good enough?)

lgrey updated this revision to Diff 354925.Jun 28 2021, 9:15 AM
lgrey marked 3 inline comments as done.

Test update

lld/test/MachO/dead-strip-align.s
14

How's this?

int3 accepted this revision.Jun 28 2021, 11:33 AM

do remember to clang-format before you land :)

lld/test/MachO/dead-strip-align.s
14

lg, thanks!

This revision was landed with ongoing or failed builds.Jun 28 2021, 7:27 PM
This revision was automatically updated to reflect the committed changes.
lld/test/MachO/dead-strip-align.s