I discovered that lld for darwin is generating the wrong code for lazy bindings in the __stub_helper section (at least for osx 10.12). This is the way i can reproduce this problem, using this program:
#include <stdio.h>
int main(int argc, char **argv) {
printf("C: printf!\n");
puts("C: puts!\n");
return 0;
}
Then I link it using i have tested it in 3.9, 4.0 and 4.1 versions:
clang -c hello.c
lld -flavor darwin hello.o -o h1 -lc
When i execute the binary h1 the system gives me the following error:
C: printf!
dyld: lazy symbol binding failed: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
has segment 4 which is too large (0..3)
dyld: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment 4 which is too
large (0..3)
Trace/BPT trap: 5
Investigating the code, it seems that the problem is that the asm code generated in the file StubPass.cpp, specifically in the line [[ https://github.com/llvm-mirror/lld/blob/master/lib/ReaderWriter/MachO/StubsPass.cpp#L323 | 323 ]],when it adds, what it seems an arbitrary number (12) to the offset into the lazy bind opcodes section, but it should be calculated depending on the MachONormalizedFileBinaryWrite::lazyBindingInfo result.
I confirmed this bug by patching the code manually in the binary and writing the right offset in the asm code (__stub_helper).
This patch fixes the content of the atom that contains the assembly code when the offset is known.