ld: error: duplicate symbol: dis_info
>>> defined at i386_disasm.c:1665
>>> otool-i386_disasm.o:(dis_info)
>>> defined at arm_disasm.c:163
>>> otool-arm_disasm.o:(.bss+0x8)
ld: error: duplicate symbol: dis_info
>>> defined at i386_disasm.c:1665
>>> otool-i386_disasm.o:(dis_info)
>>> defined at arm64_disasm.c:62
>>> otool-arm64_disasm.o:(.bss+0x0)
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
When performing LTO, `ld64` reads in any LLVM bitcode files, creates
atoms for them, and compiles the bitcode files to their corresponding
in-memory Mach-O files. These Mach-O files are then
loaded (lto_file.cpp:Parser::loadMachO), and information from the atoms
in the Mach-O files is then synced to the corresponding atoms from the
LLVM bitcode files.
However, the underlying function (ld.hpp:Atom::setAttributesFromAtom)
fails to copy over the alias bit from the Mach-O symbol. This omission
means that the original LLVM atom is not correctly marked as an alias
and therefore not correctly sorted prior to the symbol it is an alias
for (order.cpp:Layout::Comparer::operator()). The end result is that
the alias symbol winds up pointing at a different symbol, with
predictably disastrous consequences when the aliased symbol is called.
This problem has been observed when performing cross-language LTO with
Firefox. See also
https://bugzilla.mozilla.org/show_bug.cgi?id=1486042#c92 for more
details.
The fix is simple: we need to copy the alias bit over, just like other
fields.
When finalizing an archive, ranlib performs the following operations:
1. stat to obtain the current mtime (pre-write mtime)
2. rewrite the timestamp in the archive header
3. utime to restore the pre-write mtime
Unfortunately, utime only supports a 1s resolution. This means that on systems
with sub-second filesystem timestamps resolution (one notable example being
APFS), the following sequence of events can happen:
1. stat to obtain the current mtime (pre-write mtime) returns hh:mm:ss.123
2. rewrite the timestamp in the archive header
3. utime to restore the pre-write mtime ends up restoring hh:mm:ss.000.
This can cause ranlib to roll back the mtime of an archive in the past instead
of moving it into the future. Given that "make" heavily relies on filesystem
timestamps to determine dependencies and required rebuilds, this can lead to
many problems. This was discovered because it caused random failures when
parallel building postgresql.
To address the issue, we attempt to use utimensat if available. This is checked
via autoconf, but on macOS this is not enough: utimensat can be present at
compile time without being available at link time, and it was only added very
recently (10.13). Inspired by how CPython is handling this, we use #pragma weak
to make the runtime dependency optional.