Is it possible to link an X64 object file to lSystem using LD such as to produce an executable that will run in Terminal or not.

'Eskimo' provided an answer to a related question a few months ago:

'How does a C program compiled from the command line link against a library in the Big Sur dynamic library cache?'

Typically, in these fora, there is a lot of rhetoric about the right and wrong ways of doing things. As a retired IT professional, I am not much interested in that. I just want to get my projects to work. Prior to Big Sur I was working on a Swift program to act as a simple IDE for Intel syntax X64 development. The user could use the app to fire up a source code editor and then compile, link and execute the resulting programs using default NASM and LD commands (or type specific commands directly into the app for execution). The Swift app would then execute the commands in Terminal and display the results. Post Big Sur and some fiddling I got the NASM commands to work again but I have tried every which way to make LD commands link the object files to the system library in order to execute system functions and cannot get beyond ‘lSystem not found’. Obviously, in this context, it is not helpful to know how to use Xcode or the C complier chain to perform such linking. Simple question, is it possible to link an X64 object file to lSystem using LD such as to produce an executable that will run in Terminal or not. I have tried, as suggested in previous answers, using the command syntax that -v offers to aid constructing the LD command line but to no avail.

Replies

<irony> With the transition to Apple silicon well underway I guess it’s time to write my first ever from-the-ground-up Intel assembly program. </irony>.

I’m running on macOS 11.2.3 (must update!) with Xcode 12.5 installed in the usual place and selected as the default command-line toolchain:

Code Block
% sw_vers
ProductName: macOS
ProductVersion: 11.2.3
BuildVersion: 20D91
% xcode-select -p
/Applications/Xcode.app/Contents/Developer


Consider this tiny assembly program:

Code Block
% cat hello.s
.section __TEXT,__text,regular,pure_instructions
.private_extern _main
.globl _main
_main:
pushq %rbp
movq %rsp, %rbp
leaq L_greeting(%rip), %rdi
callq _puts
xorl %eax, %eax
popq %rbp
retq
.section __TEXT,__cstring,cstring_literals
L_greeting:
.asciz "Hello Cruel World!"


I can assemble, link, and run it like so:

Code Block
% as -o hello.o hello.s
% clang -o hello hello.o
% ./hello
Hello Cruel World!


The trick here is to use the clang driver as the linker. This picks up the default toolchain and, from there, the macOS SDK.

If you don’t want to use clang then it’s fine to invoke ld directly. To get an idea of how to do this, run the clang driver with the -v option so that it prints each command as it executes it:

Code Block
% clang -o hello -v hello.o
Apple clang version 12.0.5 (clang-1205.0.22.9)
Target: x86_64-apple-darwin20.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_lib…


Parsing that reveals a ld invocation like this:

Code Block
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld \
-demangle \
-lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib \
-dynamic \
-arch x86_64 \
-platform_version macos 11.0.0 11.3 \
-syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk \
-o hello \
-L/usr/local/lib \
hello.o \
-lSystem \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.5/lib/darwin/libclang_rt.osx.a


The key element is the -syslibroot argument, which tells ld how to resolve imported libraries. This is what allows the -lSystem to find the right stub library (.tbd) for the System framework.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
  • I have two swift files. main.swift and other.swift. I compile them as such

    swiftc -emit-object main.swift other.swift Greet

    When I do:

    clang -o Greet main.o other.o

    I get:

    ld: warning: Could not find or use auto-linked library 'swiftFoundation' ld: warning: Could not find or use auto-linked library 'swiftDarwin' <removed for brevity> ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 

    Can you tell what's wrong?

  • This is a very different question. Please start a new thread. Tag it with Linker so that I see it.

Add a Comment
I love irony, as a retired public service person how could I not, but I love solutions that work better. Thanks, Eskimo. Clang wins.