Search code examples
macosassemblylinkerx86-64mach-o

Tell 'ld' dyld_stub_binder is no longer in libSystem.dyld but in libSystem.B.dyld


I am trying to re-create the Launchpad executable and so far everything seems right except I get this warning when I run ld:

Assembling/Linking with:

as myprogram.s -o myprogram.o
ld myprogram.o -arch x86_64 -macosx_version_min 10.12 -e _start -framework Foundation -framework ApplicationServices -o myprogram

ld: symbol dyld_stub_binder not found (normally in libSystem.dylib).  Needed to perform lazy binding to function _CoreDockSendNotification for architecture x86_64

Here is my code (sorry NASM guys, AT&T syntax here):

.section __DATA, __const
.section __TEXT, __text
.globl _start
_start:
pushq %rbp
movq %rbp, %rsp
lea lpToggle_cfstring_(%rip), %rdi
xor %esi, %esi
callq _CoreDockSendNotification
mov %rax, %r14
xor %rdi, %rdi
mov $0x2000001, %rax
syscall

.section __TEXT,__cstring,cstring_literals
lpToggle: .asciz    "com.apple.launchpad.toggle"
.section __DATA,__cfstring
lpToggle_cfstring_:
    .quad   ___CFConstantStringClassReference
    .long   1992                    
    .space  4
    .quad   lpToggle
    .quad   26 

I have updated to the latest version of of both xcode and the command line tools, I have tried changing _start to _main, I have tried to link libSystem.B.dyld directly (both with and without the '.dyld' extension):

ld lp.o -arch x86_64 -macosx_version_min 10.12 -e _start -framework Foundation -framework ApplicationServices -L/usr/lib/ -llibSystem.B.dyld -o lp

ld lp.o -arch x86_64 -macosx_version_min 10.12 -e _start -framework Foundation -framework ApplicationServices -llibSystem.B.dyld -o lp

ld lp.o -arch x86_64 -macosx_version_min 10.12 -e _start -framework Foundation -framework ApplicationServices -o lp -l/usr/lib/libSystem.B.dyld

ld lp.o -arch x86_64 -macosx_version_min 10.12 -e _start -framework Foundation -framework ApplicationServices -o lp -libSystem.B.dyld

To which I get:

ld: warning: directory not found for option '-L/usr/lib/ -llibSystem.B.dyld'

or

ld: warning: directory not found for option '-l/usr/lib/libSystem.B.dyld'

or

ld: warning: library not found for option '-l/usr/lib/libSystem.B.dyld'

Depending which one I try.

I even tried using ld directly from the /Applications/Xcode.app/Contents/Developer/usr/bin directory to see if there was a symlink issue between new and legacy

I used lldb to dump the symtab of libSystem.dyld and sure enough the line that contains:

`[  108] 108 X Undefined 0x0000000000000000 0x0000000000000000 0x00010000 dyld_stub_binder`

Which means it has a and index/user id of 108, the X means it is externally defined (probably is libSystem.B), type of Undefined, 'File Address/Value' of '0x0' no Load Address, and a flag of 0x00010000.

I loaded the Launchpad executable in Hopper to see what it was going on but it wasn't of much help (except that it told me dyld_stub_binder was in libSystem.B.dyld).

Not sure if this is pertinent but in the actual Launchpad header contains:

                         ; Load Command 4
                         ; 
    0000000100000410     struct __macho_dyld_info_command {
                             LC_DYLD_INFO_ONLY,   // LC_DYLD_INFO or LC_DYLD_INFO_ONLY
                             0x30,                // sizeof(struct dyld_info_command)
                             0x2000,              // file offset to rebase info 
                             0x8,                 // size of rebase info  
                             0x2008,              // file offset to binding info  
                             0x40,                // size of binding info 
                             0x0,                 // file offset to weak binding info  
                             0x0,                 // size of weak binding info 
                             0x2048,              // file offset to lazy binding info
                             0x20,                // size of lazy binding infs
                             0x2068,              // file offset to lazy binding info
                             0x20                 // size of lazy binding infs
                         }


                        ;Load command 7

00000001000004a8         struct __macho_dylinker_command {
                             LC_LOAD_DYLINKER,  // LC_ID_DYLINKER, LC_LOAD_DYLINKER or LC_DYLD_ENVIRONMENT
                             0x20,  // includes pathname string
                             0xc    // dynamic linker's path name (should be 12)
                         }
00000001000004b4         db         "/usr/lib/dyld", 0
00000001000004c2         db  0x00 ; '.'
00000001000004c3         db  0x00 ; '.'
00000001000004c4         db  0x00 ; '.'
00000001000004c5         db  0x00 ; '.'
00000001000004c6         db  0x00 ; '.'
00000001000004c7         db  0x00 ; '.'   

In the _stub_helper section (which looks like some sort of infinite-ish loop completely skipping the middle 4 instructions):

0000000100000f80   lea,  qword [dyld_stub_binder_100001000+8]; CODE XREF=0x100000f95
0000000100000f87   push  r11
0000000100000f89   jmp   qword [dyld_stub_binder_100001000] ; dyld_stub_binder
0000000100000f8f   db         0x90
0000000100000f90   push       0x0
0000000100000f95   jmp        0x100000f80

In the __DATA__nl_symbol_ptr section :

0000000100001000         dq  dyld_stub_binder  ; DATA XREF=0x100000f89
0000000100001008         dq  0x0000000000000000 ; DATA XREF=0x100000f80

In the External Symbols segment:

                 dyld_stub_binder:
0000000100005010         db  0x00 ; '.' ; in /usr/lib/libSystem.B.dylib, CODE XREF=0x100000f89DATA XREF=dyld_stub_binder_100001000
0000000100005011         db  0x00 ; '.'
0000000100005012         db  0x00 ; '.'
0000000100005013         db  0x00 ; '.'
0000000100005014         db  0x00 ; '.'
0000000100005015         db  0x00 ; '.'
0000000100005016         db  0x00 ; '.'
0000000100005017         db  0x00 ; '.'

What is more interesting is that if I compile with gcc:

gcc -arch x86_64 -e _start -framework Foundation -framework ApplicationServices lp.s

It will build with no problems however will segfault at some point during runtime. I say at some point because if I load it with lldb a.out and do the run command, it executes just as it should, no segfault. So it is hard to find out what is going on where exactly.My hunch is that lldb is pointing my application to the correctdyld_stub_binder but I could be wrong.

However it runs perfectly fine if I run sudo ./myfile on the gcc build. What is gcc doing that ld is not? Or is it something in the as command?

I am still relatively new to using core macOS assembly so any pointers would be helpful!

P.S. I did also try -no_weak_imports but that did not work either


Solution

  • Your ld myprogram.o -arch x86_64 -macosx_version_min 10.12 -e _start -framework Foundation -framework ApplicationServices -o myprogram is missing -l search option for libSystem.B library.
    Add either of these:

    -lsystem.b
    -lsystem
    -lc
    -lm
    -ld
    

    All are synonyms which will solve missing LC_LOAD_DYLIB(libSystem.B.dylib) load command. Btw your program works :-)