[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

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:

  char foo[0xd78] = {0};


  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.

  rLLD LLVM Linker



-------------- 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