diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -81,7 +81,31 @@ if (read32be(&hdr->magic) != MachO::FAT_MAGIC) return mbref; - error("TODO: Add support for universal binaries"); + // Object files and archive files may be fat files, which contains + // multiple real files for different CPU ISAs. Here, we search for a + // file that matches with the current link target and returns it as + // a MemoryBufferRef. + auto *arch = reinterpret_cast(buf + sizeof(*hdr)); + + for (uint32_t i = 0, n = read32be(&hdr->nfat_arch); i < n; ++i) { + if (reinterpret_cast(arch + i + 1) > + buf + mbref.getBufferSize()) { + error(path + ": fat_arch struct extends beyond end of file"); + return None; + } + + if (read32be(&arch[i].cputype) != target->cpuType || + read32be(&arch[i].cpusubtype) != target->cpuSubtype) + continue; + + uint32_t offset = read32be(&arch[i].offset); + uint32_t size = read32be(&arch[i].size); + if (offset + size > mbref.getBufferSize()) + error(path + ": slice extends beyond end of file"); + return MemoryBufferRef(StringRef(buf + offset, size), path.copy(bAlloc)); + } + + error("unable to find matching architecture in " + path); return None; } diff --git a/lld/test/CMakeLists.txt b/lld/test/CMakeLists.txt --- a/lld/test/CMakeLists.txt +++ b/lld/test/CMakeLists.txt @@ -35,8 +35,9 @@ if (NOT LLD_BUILT_STANDALONE) list(APPEND LLD_TEST_DEPS FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-cvtres - llvm-dis llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump - llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt yaml2obj + llvm-dis llvm-dwarfdump llvm-lib llvm-lipo llvm-mc llvm-nm llvm-objcopy + llvm-objdump llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt + yaml2obj ) endif() diff --git a/lld/test/MachO/fat-arch.s b/lld/test/MachO/fat-arch.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/fat-arch.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i386-apple-darwin %s -o %t.i386.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.x86_64.o +# RUN: llvm-lipo %t.i386.o %t.x86_64.o -create -o %t.fat.o +# RUN: lld -flavor darwinnew -arch x86_64 -o /dev/null %t.fat.o + +# RUN: llvm-lipo %t.i386.o -create -o %t.noarch.o +# RUN: not lld -flavor darwinnew -arch x86_64 -o /dev/null %t.noarch.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.noarch.o +# CHECK: error: unable to find matching architecture in [[FILE]] + +.text +.global _main +_main: + mov $0, %eax + ret diff --git a/lld/test/MachO/invalid-fat-narch.s b/lld/test/MachO/invalid-fat-narch.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid-fat-narch.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: yaml2obj %s -o %t.o +# RUN: not lld -flavor darwinnew -arch x86_64 -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.o +# CHECK: error: [[FILE]]: fat_arch struct extends beyond end of file + +!fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: +Slices: diff --git a/lld/test/MachO/invalid-fat-offset.s b/lld/test/MachO/invalid-fat-offset.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid-fat-offset.s @@ -0,0 +1,22 @@ +# REQUIRES: x86 +# RUN: yaml2obj %s -o %t.o +# RUN: not lld -flavor darwinnew -arch x86_64 -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.o +# CHECK: error: [[FILE]]: slice extends beyond end of file + +!fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: + - cputype: 0x01000007 + cpusubtype: 0x00000003 + offset: 0x0000000000001000 + size: 0 + align: 12 + - cputype: 0x00000007 + cpusubtype: 0x00000003 + offset: 0x000000000000B000 + size: 0 + align: 12 +Slices: