Darwin localhost 21.6.0 Darwin Kernel Version 21.6.0: Mon Aug 22 20:17:10 PDT 2022; root:xnu-8020.140.49~2/RELEASE_X86_64 x86_64
@(#)PROGRAM:ld PROJECT:ld64-820.1
BUILD 18:42:34 Sep 11 2022
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
LTO support using: LLVM version 14.0.0, (clang-1400.0.29.202) (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 14.0.0 (tapi-1400.0.11)
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
I used uasm 2.56.2 release package.
The assembly file, t.asm.
.code
Foo struct
f1 dd ?
f2 dd ?
Foo ends
_r2 proc
mov rax, 42
ret
_r2 endp
_rx proc
mov rax, (SIZEOF Foo)
ret
_rx endp
end
The struct Foo is used in _rx.
The the C file, m.c.
#include <stdio.h>
#include <stdlib.h>
int rx();
int main() {
printf("%d\n", rx());
}
cc -o m m.c t.o
Undefined symbols for architecture x86_64:
"_rx", referenced from:
_main in m-d22313.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ld complained that _rx was not found. I checked it with nm:
$ nm t.o
0000000000000000 s Foo
0000000000000000 T _r2
0000000000000008 T _rx
It is there. Now the fun part:
I removed _r2 function from t.asm. Now it looks like:
.code
Foo struct
f1 dd ?
f2 dd ?
Foo ends
_rx proc
mov rax, (SIZEOF Foo)
ret
_rx endp
end
and as you can see, there are TWOcallq 0x100003f80 calls.
nm solved the myst:
$ nm ./m
0000000100008008 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100003f40 T _main
U _printf
0000000100003f80 T _rx
U dyld_stub_binder
_rx is there, but it is EMPTY. Now again the fun part number 2, I changed t.asm a little bit: remove the usage of struct Foo:
.code
Foo struct
f1 dd ?
f2 dd ?
Foo ends
_rx proc
mov rax, 42; (SIZEOF Foo)
ret
_rx endp
end
then compiled both files again and ran m:
$ ./m
42
I spent many hours on why this happened before I got this minimal test case. The reason, I guess, is ld uses the definition of struct Foo to link against _rx. I am no expert on the format of macho-64, the workaround I have found is not to output the type to the result .o file.
Now everything works with the original t.asm and m.c.
$ uasm -nologo -macho64 t.asm
$ cc -o m m.c t.o
$ ./m
8
nm's output looks fine:
$ nm m
0000000100008008 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100003f00 T _main
U _printf
0000000100003f40 T _r2
0000000100003f48 T _rx
U dyld_stub_binder
My environment:
I used uasm 2.56.2 release package.
The assembly file,
t.asm
.The
struct Foo
is used in_rx
.The the C file,
m.c
.Then compile them:
and
ld
complained that_rx
was not found. I checked it withnm
:It is there. Now the fun part:
I removed
_r2
function fromt.asm
. Now it looks like:then compiled both files:
The link was successful, but it crashed:
I disassembled the output
m
with objdump:and as you can see, there are TWO
callq 0x100003f80
calls.nm
solved the myst:_rx
is there, but it is EMPTY. Now again the fun part number 2, I changedt.asm
a little bit: remove the usage ofstruct Foo
:then compiled both files again and ran
m
:I spent many hours on why this happened before I got this minimal test case. The reason, I guess, is
ld
uses the definition ofstruct Foo
to link against_rx
. I am no expert on the format of macho-64, the workaround I have found is not to output the type to the result.o
file.then in
macho_build_string_tbl
, don't touch the counters ifmacho_add_string
returns0
like this:Now everything works with the original
t.asm
andm.c
.nm
's output looks fine:The disassembled output is good: