; REQUIRES: x86
; RUN: rm -rf %t; split-file %s %t

; RUN: llvm-as %t/framework.ll -o %t/framework.o
; RUN: %lld -lSystem %t/framework.o -o %t/frame
; RUN: llvm-otool -l %t/frame | FileCheck --check-prefix=FRAME %s \
; RUN:  --implicit-check-not LC_LOAD_DYLIB
; FRAME:          cmd LC_LOAD_DYLIB
; FRAME-NEXT: cmdsize
; FRAME-NEXT:    name /usr/lib/libSystem.dylib
; FRAME:          cmd LC_LOAD_DYLIB
; FRAME-NEXT: cmdsize
; FRAME-NEXT:    name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation

; RUN: not %lld %t/framework.o -o %t/frame_no_autolink -ignore_auto_link 2>&1 | FileCheck --check-prefix=NO-AUTOLINK %s
; RUN: not %lld %t/framework.o -o %t/frame_no_autolink --ignore-auto-link-option CoreFoundation 2>&1 | FileCheck --check-prefix=NO-AUTOLINK %s
; RUN: not %lld %t/framework.o -o %t/frame_no_autolink --ignore-auto-link-option=CoreFoundation 2>&1 | FileCheck --check-prefix=NO-AUTOLINK %s
; NO-AUTOLINK: error: undefined symbol: __CFBigNumGetInt128

; RUN: llvm-as %t/l.ll -o %t/l.o
;; The dynamic call to _CFBigNumGetInt128 uses dyld_stub_binder,
;; which needs -lSystem from LC_LINKER_OPTION to get resolved.
;; The reference to __cxa_allocate_exception will require -lc++ from
;; LC_LINKER_OPTION to get resolved.
; RUN: %no-lsystem-lld %t/l.o -o %t/l -framework CoreFoundation
; RUN: llvm-otool -l %t/l | FileCheck --check-prefix=LIB %s \
; RUN:  --implicit-check-not LC_LOAD_DYLIB
; LIB:          cmd LC_LOAD_DYLIB
; LIB-NEXT: cmdsize
; LIB-NEXT:    name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
; LIB:          cmd LC_LOAD_DYLIB
; LIB-NEXT: cmdsize
; LIB-NEXT:    name /usr/lib/libSystem.dylib
; LIB:          cmd LC_LOAD_DYLIB
; LIB-NEXT: cmdsize
; LIB-NEXT:    name /usr/lib/libc++abi.dylib

;; Check that we don't create duplicate LC_LOAD_DYLIBs.
; RUN: %no-lsystem-lld -lSystem %t/l.o -o %t/l -framework CoreFoundation
; RUN: llvm-otool -l %t/l | FileCheck --check-prefix=LIB2 %s \
; RUN:  --implicit-check-not LC_LOAD_DYLIB
; LIB2:          cmd LC_LOAD_DYLIB
; LIB2-NEXT: cmdsize
; LIB2-NEXT:    name /usr/lib/libSystem.dylib
; LIB2:          cmd LC_LOAD_DYLIB
; LIB2-NEXT: cmdsize
; LIB2-NEXT:    name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
; LIB2:          cmd LC_LOAD_DYLIB
; LIB2-NEXT: cmdsize
; LIB2-NEXT:    name /usr/lib/libc++abi.dylib

; RUN: llvm-as %t/invalid.ll -o %t/invalid.o
; RUN: not %lld %t/invalid.o -o /dev/null 2>&1 | FileCheck --check-prefix=INVALID %s
; INVALID: error: -why_load is not allowed in LC_LINKER_OPTION

;; This is a regression test for a dangling string reference issue that occurred
;; when loading an archive-based framework via LC_LINKER_OPTION (see
;; D111706). Prior to the fix, this would trigger a heap-use-after-free when run
;; under ASAN.
; RUN: llc %t/foo.ll -o %t/foo.o -filetype=obj
; RUN: mkdir -p %t/Foo.framework
;; In a proper framework, this is technically supposed to be a symlink to the
;; actual archive at Foo.framework/Versions/Current, but we skip that here so
;; that this test can run on Windows.
; RUN: llvm-ar rcs %t/Foo.framework/Foo %t/foo.o
; RUN: llc %t/load-framework-foo.ll -o %t/load-framework-foo.o -filetype=obj
; RUN: llc %t/load-framework-undefined-symbol.ll -o %t/load-framework-undefined-symbol.o -filetype=obj
; RUN: llc %t/load-missing.ll -o %t/load-missing.o -filetype=obj
; RUN: llc %t/main.ll -o %t/main.o -filetype=obj
; RUN: %lld %t/load-framework-foo.o %t/main.o -o %t/main -F%t
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS

;; Make sure -all_load and -ObjC have no effect on libraries loaded via
;; LC_LINKER_OPTION flags.
; RUN: llc %t/load-library-foo.ll -o %t/load-library-foo.o -filetype=obj
; RUN: llvm-ar rcs %t/libfoo.a %t/foo.o
; RUN: %lld -all_load -ObjC %t/load-framework-foo.o %t/load-library-foo.o \
; RUN:   %t/main.o -o %t/main -F%t -L%t
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS

;; Note that _OBJC_CLASS_$_TestClass is *not* included here.
; SYMS:       SYMBOL TABLE:
; SYMS-NEXT:  g     F __TEXT,__text _main
; SYMS-NEXT:  g     F __TEXT,__text __mh_execute_header
; SYMS-NEXT:  *UND* dyld_stub_binder
; SYMS-EMPTY:

;; Make sure -all_load has effect when libraries are loaded via LC_LINKER_OPTION flags and explicitly passed as well
; RUN: %lld -all_load %t/load-framework-foo.o %t/load-library-foo.o %t/main.o -o %t/main -F%t -L%t -lfoo
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS-ALL-LOAD

;; Note that _OBJC_CLASS_$_TestClass is *included* here.
; SYMS-ALL-LOAD:       SYMBOL TABLE:
; SYMS-ALL-LOAD-NEXT:  g     F __TEXT,__text _main
; SYMS-ALL-LOAD-NEXT:  g     O __DATA,__objc_data _OBJC_CLASS_$_TestClass
; SYMS-ALL-LOAD-NEXT:  g     F __TEXT,__text __mh_execute_header
; SYMS-ALL-LOAD-NEXT:  *UND* dyld_stub_binder
; SYMS-ALL-LOAD-EMPTY:

;; Make sure -force_load has effect when libraries are loaded via LC_LINKER_OPTION flags and explicitly passed as well
; RUN: %lld %t/load-library-foo.o %t/main.o -o %t/main -F%t -L%t -force_load %t/libfoo.a
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS-FORCE-LOAD

;; Note that _OBJC_CLASS_$_TestClass is *included* here.
; SYMS-FORCE-LOAD:       SYMBOL TABLE:
; SYMS-FORCE-LOAD-NEXT:  g     F __TEXT,__text _main
; SYMS-FORCE-LOAD-NEXT:  g     O __DATA,__objc_data _OBJC_CLASS_$_TestClass
; SYMS-FORCE-LOAD-NEXT:  g     F __TEXT,__text __mh_execute_header
; SYMS-FORCE-LOAD-NEXT:  *UND* dyld_stub_binder
; SYMS-FORCE-LOAD-EMPTY:

;; Make sure -ObjC has effect when frameworks are loaded via LC_LINKER_OPTION flags and explicitly passed as well
; RUN: %lld -ObjC %t/load-framework-foo.o %t/load-library-foo.o %t/main.o -o %t/main -F%t -L%t -framework Foo
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS-OBJC-LOAD

;; Note that _OBJC_CLASS_$_TestClass is *included* here.
; SYMS-OBJC-LOAD:       SYMBOL TABLE:
; SYMS-OBJC-LOAD-NEXT:  g     F __TEXT,__text _main
; SYMS-OBJC-LOAD-NEXT:  g     O __DATA,__objc_data _OBJC_CLASS_$_TestClass
; SYMS-OBJC-LOAD-NEXT:  g     F __TEXT,__text __mh_execute_header
; SYMS-OBJC-LOAD-NEXT:  *UND* dyld_stub_binder
; SYMS-OBJC-LOAD-EMPTY:

;; Make sure that frameworks containing object files or bitcode instead of
;; dylibs or archives do not cause duplicate symbol errors
; RUN: mkdir -p %t/Foo.framework
; RUN: llc --filetype=obj %t/foo.ll -o %t/Foo.framework/Foo
; RUN: llc --filetype=obj %t/load-framework-twice.ll -o %t/main
;; Order of the object with the LC_LINKER_OPTION vs -framework arg is important.
; RUN: %lld %t/main -F %t -framework Foo -framework Foo -o /dev/null
; RUN: %lld -F %t -framework Foo -framework Foo %t/main -o /dev/null

; RUN: llvm-as %t/foo.ll -o %t/Foo.framework/Foo
; RUN: llvm-as %t/load-framework-twice.ll -o %t/main
;; Order of the object with the LC_LINKER_OPTION vs -framework arg is important.
; RUN: %lld %t/main -F %t -framework Foo -framework Foo -o /dev/null
; RUN: %lld -F %t -framework Foo -framework Foo %t/main -o /dev/null

;; Checks that "framework not found" errors from LC_LINKER_OPTIONS are not
;; emitted unless the link fails or --strict-auto-link is passed.
; RUN: %lld -ObjC %t/load-framework-foo.o %t/main.o -o %t/main-no-foo.out
; RUN: llvm-objdump --macho --syms %t/main-no-foo.out | FileCheck %s --check-prefix=SYMS-NO-FOO
; RUN: not %lld --strict-auto-link -ObjC %t/load-missing.o %t/main.o -o %t/main-no-foo.out 2>&1 \
; RUN:   | FileCheck %s --check-prefix=MISSING-AUTO-LINK
; RUN: %no-fatal-warnings-lld --strict-auto-link -ObjC %t/load-missing.o %t/main.o -o %t/main-no-foo.out 2>&1 \
; RUN:   | FileCheck %s --check-prefix=MISSING-AUTO-LINK
; RUN: not %lld -ObjC %t/load-framework-undefined-symbol.o %t/load-missing.o %t/main.o -o %t/main-no-foo.out 2>&1 \
; RUN:   | FileCheck %s --check-prefixes=UNDEFINED-SYMBOL,MISSING-AUTO-LINK

;; Verify that nothing from the framework is included.
; SYMS-NO-FOO:       SYMBOL TABLE:
; SYMS-NO-FOO-NEXT:  g     F __TEXT,__text _main
; SYMS-NO-FOO-NOT:   g     O __DATA,__objc_data _OBJC_CLASS_$_TestClass

; UNDEFINED-SYMBOL: undefined symbol: __SomeUndefinedSymbol
; MISSING-AUTO-LINK: {{.+}}: auto-linked framework not found for -framework Foo
; MISSING-AUTO-LINK: {{.+}}: auto-linked library not found for -lBar

;--- framework.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-framework", !"CoreFoundation"}
!llvm.linker.options = !{!0}

declare void @_CFBigNumGetInt128(...)

define void @main() {
  call void @_CFBigNumGetInt128()
  ret void
}

;--- l.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-lSystem"}
!1 = !{!"-lc++"}
!llvm.linker.options = !{!0, !0, !1}

declare void @_CFBigNumGetInt128(...)
declare ptr @__cxa_allocate_exception(i64)

define void @main() {
  call void @_CFBigNumGetInt128()
  call ptr @__cxa_allocate_exception(i64 4)
  ret void
}

;--- invalid.ll

target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-why_load"}
!llvm.linker.options = !{!0}

define void @main() {
  ret void
}

;--- load-framework-foo.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-framework", !"Foo"}
!llvm.linker.options = !{!0}

;--- load-missing.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-framework", !"Foo"}
!1 = !{!"-lBar"}
!llvm.linker.options = !{!0, !1}

;--- load-framework-undefined-symbol.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

declare void @_SomeUndefinedSymbol(...)
define void @foo() {
  call void @_SomeUndefinedSymbol()
  ret void
}

;--- load-framework-twice.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-framework", !"Foo"}
!llvm.linker.options = !{!0, !0}

define void @main() {
  ret void
}

;--- load-library-foo.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

!0 = !{!"-lfoo"}
!llvm.linker.options = !{!0}

;--- main.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

define void @main() {
  ret void
}

!0 = !{!"-framework", !"Foo"}
!llvm.linker.options = !{!0}

;--- foo.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

%struct._class_t = type {}
@"OBJC_CLASS_$_TestClass" = global %struct._class_t {}, section "__DATA, __objc_data", align 8
