[PATCH] D58083: lld: Fix initial Mach-O load commands size calculation omitting LC_FUNCTION_STARTS
Nicholas Allegra via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 11 16:10:12 PST 2019
comex created this revision.
comex added reviewers: pete, lhames.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
The Mach-O writer calculates the size of load commands multiple times.
First, Util::assignAddressesToSections() (in MachONormalizedFileFromAtoms.cpp)
calculates the size using headerAndLoadCommandsSize() (in
MachONormalizedFileBinaryWriter.cpp), which creates a temporary MachOFileLayout
for the NormalizedFile, only to retrieve its headerAndLoadCommandsSize. Later,
writeBinary() (in MachONormalizedFileBinaryWriter.cpp) creates a new layout and
uses the offsets from that layout to actually write out everything in the
NormalizedFile.
But the NormalizedFile changes between the first computation and the second.
When Util::assignAddressesToSections is called, file.functionStarts is always
empty because Util::addFunctionStarts has not yet been called. Yet
MachOFileLayout decides whether to include a LC_FUNCTION_STARTS command based
on whether file.functionStarts is nonempty. Therefore, the initial computation
always omits it.
Because padding for the __TEXT segment (to make its size a multiple of the page
size) is added between the load commands and the first section, LLD still
generates a valid binary as long as the amount of padding happens to be large
enough to fit LC_FUNCTION_STARTS command, which it usually is.
However, it's easy to reproduce the issue by adding a section of a precise
size. Given foo.c:
__attribute__((section("__TEXT,__foo")))
char foo[0xd78] = {0};
Run:
clang -dynamiclib -o foo.dylib foo.c -fuse-ld=lld -install_name /usr/lib/foo.dylib
otool -lvv foo.dylib
This should produce:
truncated or malformed object (offset field of section 1 in LC_SEGMENT_64
command 0 not past the headers of the file)
This commit:
- Changes MachOFileLayout to always assume LC_FUNCTION_STARTS is present for the initial computation, as long as generating LC_FUNCTION_STARTS is enabled. It would be slightly better to check whether there are actually any functions, since no LC_FUNCTION_STARTS will be generated if not, but it doesn't cause a problem if the initial computation is too high.
- Adds a test.
- Adds an assert in MachOFileLayout::writeSectionContent() that we are not writing section content into the load commands region (which would happen if the offset was calculated too low due to the initial load commands size calculation being too low).
- Adds an assert in MachOFileLayout::writeLoadCommands to validate a similar situation where two size-of-load-commands computations are expected to be equivalent.
Repository:
rLLD LLVM Linker
https://reviews.llvm.org/D58083
Files:
lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
lld/test/mach-o/load-commands-size.yaml
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D58083.186357.patch
Type: text/x-patch
Size: 26511 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190212/57d90ab4/attachment.bin>
More information about the llvm-commits
mailing list