public
Last active

Create a macho dynamically linked executable WITHOUT any linked, dynamic libraries!

  • Download Gist
build steps
1 2 3
clang -o main.o -c main.c -g -Os
clang -o dyld_stub_binder.o -c dyld_stub_binder.s -g
patched_ld64 -o main main.o dyld_stub_binder.o -macosx_version_min 10.8.0 -undefined dynamic_lookup
dyld_stub_binder.s
GAS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
// taken from dyld sources. note that the call to dyld_fast_stub_entry now goes through a function pointer
/*
* Copyright (c) 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#define MH_PARAM_BP 8
#define LP_PARAM_BP 16
 
#define RDI_SAVE 0
#define RSI_SAVE 8
#define RDX_SAVE 16
#define RCX_SAVE 24
#define R8_SAVE 32
#define R9_SAVE 40
#define RAX_SAVE 48
#define XMMM0_SAVE 64 /* 16-byte align */
#define XMMM1_SAVE 80
#define XMMM2_SAVE 96
#define XMMM3_SAVE 112
#define XMMM4_SAVE 128
#define XMMM5_SAVE 144
#define XMMM6_SAVE 160
#define XMMM7_SAVE 176
#define STACK_SIZE 192 /* (XMMM7_SAVE+16) must be 16 byte aligned too */
 
/*
* sp+4 lazy binding info offset
* sp+0 address of ImageLoader cache
*/
.align 2,0x90
.globl dyld_stub_binder
dyld_stub_binder:
pushq %rbp
movq %rsp,%rbp
subq $STACK_SIZE,%rsp # at this point stack is 16-byte aligned because two meta-parameters where pushed
movq %rdi,RDI_SAVE(%rsp) # save registers that might be used as parameters
movq %rsi,RSI_SAVE(%rsp)
movq %rdx,RDX_SAVE(%rsp)
movq %rcx,RCX_SAVE(%rsp)
movq %r8,R8_SAVE(%rsp)
movq %r9,R9_SAVE(%rsp)
movq %rax,RAX_SAVE(%rsp)
misaligned_stack_error_entering_dyld_stub_binder:
movdqa %xmm0,XMMM0_SAVE(%rsp)
movdqa %xmm1,XMMM1_SAVE(%rsp)
movdqa %xmm2,XMMM2_SAVE(%rsp)
movdqa %xmm3,XMMM3_SAVE(%rsp)
movdqa %xmm4,XMMM4_SAVE(%rsp)
movdqa %xmm5,XMMM5_SAVE(%rsp)
movdqa %xmm6,XMMM6_SAVE(%rsp)
movdqa %xmm7,XMMM7_SAVE(%rsp)
dyld_stub_binder_:
movq MH_PARAM_BP(%rbp),%rdi # call fastBindLazySymbol(loadercache, lazyinfo)
movq LP_PARAM_BP(%rbp),%rsi
call *(_fast_stub_entry)
movq %rax,%r11 # save target
movdqa XMMM0_SAVE(%rsp),%xmm0 # restore registers
movdqa XMMM1_SAVE(%rsp),%xmm1
movdqa XMMM2_SAVE(%rsp),%xmm2
movdqa XMMM3_SAVE(%rsp),%xmm3
movdqa XMMM4_SAVE(%rsp),%xmm4
movdqa XMMM5_SAVE(%rsp),%xmm5
movdqa XMMM6_SAVE(%rsp),%xmm6
movdqa XMMM7_SAVE(%rsp),%xmm7
movq RDI_SAVE(%rsp),%rdi
movq RSI_SAVE(%rsp),%rsi
movq RDX_SAVE(%rsp),%rdx
movq RCX_SAVE(%rsp),%rcx
movq R8_SAVE(%rsp),%r8
movq R9_SAVE(%rsp),%r9
movq RAX_SAVE(%rsp),%rax
addq $STACK_SIZE,%rsp
popq %rbp
addq $16,%rsp # remove meta-parameters
jmp *%r11 # jmp to target
ld64 patch
1 2 3 4 5 6 7 8 9 10 11
--- a/src/ld/InputFiles.cpp 2013-01-15 16:39:18.000000000 -0500
+++ b/src/ld/InputFiles.cpp 2013-01-23 18:47:09.000000000 -0500
@@ -1220,8 +1220,8 @@
state.bundleLoader = _bundleLoader;
// <rdar://problem/10807040> give an error when -nostdlib is used and libSystem is missing
- if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() )
- throw "dynamic main executables must link with libSystem.dylib";
+ //if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() )
+ // throw "dynamic main executables must link with libSystem.dylib";
}
main.c
C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
 
struct ProgramVars; /* forward reference */
typedef void *(*dlopen_t)(const char *path, int mode);
void *fast_stub_entry;
 
struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
 
static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
 
 
static int my_dyld_func_lookup(const char* dyld_func_name, void **address)
{
return (*myDyldSection.lookup)(dyld_func_name, address);
}
 
__attribute__((constructor))
void ctor(int argc, const char* argv[], const char* envp[], const char* apple[], const struct ProgramVars* vars) {
void *dlopen_addr;
my_dyld_func_lookup("__dyld_dlopen", &dlopen_addr);
my_dyld_func_lookup("__dyld_fast_stub_entry", &fast_stub_entry);
 
((dlopen_t)dlopen_addr)("/usr/lib/libSystem.B.dylib", RTLD_LAZY);
printf("in ctor, completed loading libSystem\n");
}
 
int main(void) {
printf("in main\n");
return 0;
}
output
1 2 3 4 5 6
dyld: calling initializer function 0x1dac in /Users/jsweval/code/firstexec/nolibs/./main
dyld: calling initializer function 0x7fff8ef4e720 in /usr/lib/libc++.1.dylib
dyld: calling initializer function 0x7fff8ef713b0 in /usr/lib/libc++.1.dylib
dyld: calling initializer function 0x7fff8d386a81 in /usr/lib/libSystem.B.dylib
in ctor, completed loading libSystem
in main

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.