18 |
|
|
19 |
*/ |
*/ |
20 |
|
|
|
/* Kinda primitive and temporary support for fasloading on Mac OS X |
|
|
Aurelien Chanudet (aurelienDOTchanudetATm4xDOTorg) */ |
|
|
|
|
21 |
#include <string.h> |
#include <string.h> |
22 |
#include <stdlib.h> |
#include <stdlib.h> |
23 |
#include <stdio.h> |
#include <stdio.h> |
29 |
#include <mach/mach.h> |
#include <mach/mach.h> |
30 |
#include <mach-o/loader.h> |
#include <mach-o/loader.h> |
31 |
#include <mach-o/dyld.h> |
#include <mach-o/dyld.h> |
|
#include <mach-o/nlist.h> |
|
32 |
|
|
33 |
#include "ptable.h" |
#include "ptable.h" |
34 |
|
|
35 |
|
typedef int (*func) (); |
36 |
|
|
37 |
|
object sSAmacosx_ldcmdA = 0L; |
38 |
|
|
39 |
static void sfasl_error (char *format, ...) |
static void sfasl_error (char *format, ...) |
40 |
{ |
{ |
41 |
va_list ap; |
va_list ap; |
48 |
exit (1); |
exit (1); |
49 |
} |
} |
50 |
|
|
51 |
/* TODO : update to reflect the improvements of Mach-O */ |
static void get_init_name (object faslfile, char *init_fun) |
|
|
|
|
int seek_to_end_ofile (FILE *fp) |
|
|
{ |
|
|
struct mach_header mach_header; |
|
|
char *hdrbuf; |
|
|
struct load_command *load_command; |
|
|
struct segment_command *segment_command; |
|
|
struct section *section; |
|
|
struct symtab_command *symtab_command; |
|
|
struct symseg_command *symseg_command; |
|
|
int len, cmd, seg; |
|
|
int end_sec, end_ofile; |
|
|
|
|
|
#ifdef DEBUG |
|
|
fprintf(stderr,"seeking to end of Mach-O file\n"); |
|
|
#endif |
|
|
|
|
|
end_ofile = 0; |
|
|
fseek(fp, 0L, 0); |
|
|
len = fread((char *)&mach_header, sizeof(struct mach_header), 1, fp); |
|
|
if (len == 1 && mach_header.magic == MH_MAGIC) { |
|
|
/* hdrbuf = (char *)malloc(mach_header.sizeofcmds); */ |
|
|
hdrbuf = (char *)alloca(mach_header.sizeofcmds); |
|
|
len = fread(hdrbuf, mach_header.sizeofcmds, 1, fp); |
|
|
if (len != 1) { |
|
|
fprintf(stderr, "seek_to_end_ofile(): failure reading Mach-O load commands\n"); |
|
|
return 0; |
|
|
} |
|
|
load_command = (struct load_command *) hdrbuf; |
|
|
for (cmd = 0; cmd < mach_header.ncmds; ++cmd) { |
|
|
switch (load_command->cmd) { |
|
|
case LC_SEGMENT: |
|
|
segment_command = (struct segment_command *) load_command; |
|
|
section = (struct section *) ((char *)(segment_command + 1)); |
|
|
for (seg = 0; seg < segment_command->nsects; ++seg, ++section) { |
|
|
end_sec = section->offset + section->size; |
|
|
if (end_sec > end_ofile) |
|
|
end_ofile = end_sec; |
|
|
} |
|
|
break; |
|
|
case LC_SYMTAB: |
|
|
symtab_command = (struct symtab_command *) load_command; |
|
|
end_sec = symtab_command->symoff + symtab_command->nsyms * sizeof(struct nlist); |
|
|
if (end_sec > end_ofile) |
|
|
end_ofile = end_sec; |
|
|
end_sec = symtab_command->stroff + symtab_command->strsize; |
|
|
if (end_sec > end_ofile) |
|
|
end_ofile = end_sec; |
|
|
break; |
|
|
case LC_SYMSEG: |
|
|
symseg_command = (struct symseg_command *) load_command; |
|
|
end_sec = symseg_command->offset + symseg_command->size; |
|
|
if (end_sec > end_ofile) |
|
|
end_ofile = end_sec; |
|
|
break; |
|
|
} |
|
|
load_command = (struct load_command *) |
|
|
((char *)load_command + load_command->cmdsize); |
|
|
} |
|
|
/* free(hdrbuf); */ |
|
|
fseek(fp, end_ofile, 0); |
|
|
return 1; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void get_init_name (object faslfile, char *init_fun) |
|
52 |
{ |
{ |
53 |
object path = coerce_to_pathname (faslfile); |
object path = coerce_to_pathname (faslfile); |
54 |
char *p; |
char *p; |
55 |
|
|
56 |
strcpy (init_fun,"init_"); |
strcpy (init_fun, "_init_"); |
57 |
coerce_to_filename (path->pn.pn_name,init_fun+5); |
coerce_to_filename (path->pn.pn_name, init_fun + 6); |
|
|
|
|
p = init_fun +5; |
|
58 |
|
|
59 |
while(*p) { |
for (p = init_fun + 6 ; *p ; p++) |
60 |
if (*p == '-') *p = '_'; |
if (*p == '-') *p = '_'; |
|
p++; |
|
|
} |
|
61 |
} |
} |
62 |
|
|
63 |
typedef int (*func) (); |
static func prepare_bundle (object faslfile, char *filename) |
|
|
|
|
func prepare_bundle (object faslfile, char *filename) |
|
64 |
{ |
{ |
65 |
NSObjectFileImage image; |
NSObjectFileImage image; |
66 |
NSModule module; |
NSModule module; |
67 |
NSSymbol nssym; |
NSSymbol nssym; |
68 |
int (*fptr) (); |
int (*fptr) (); |
69 |
|
|
70 |
unsigned long i, n, image_count; |
unsigned long n; |
|
unsigned long vmaddr_slide; |
|
|
struct mach_header *header; |
|
71 |
unsigned long vmsize = 0; |
unsigned long vmsize = 0; |
72 |
struct load_command *lc; |
unsigned long vmaddr_slide = 0; |
73 |
|
unsigned long base_addr = (unsigned long) -1; |
74 |
|
|
75 |
extern void mark_region (unsigned long address, unsigned long size); |
extern void mark_region (unsigned long address, unsigned long size); |
76 |
|
|
78 |
sfasl_error ("cannot create object file image\n"); |
sfasl_error ("cannot create object file image\n"); |
79 |
} |
} |
80 |
|
|
81 |
if (!(module = NSLinkModule (image, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR))) { |
if (!(module = NSLinkModule (image, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR | |
82 |
|
NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW))) { |
83 |
sfasl_error ("cannot link bundle\n"); |
sfasl_error ("cannot link bundle\n"); |
84 |
} |
} |
85 |
|
|
86 |
if (!(nssym = NSLookupSymbolInModule (module, "_init_code"))) |
if (!(nssym = NSLookupSymbolInModule (module, "_init_code"))) |
87 |
{ |
{ |
88 |
char init_fun [201]; |
char init_fun [256]; |
89 |
|
|
90 |
init_fun[0] = '_'; |
get_init_name (faslfile, init_fun); |
|
get_init_name (faslfile, &init_fun[1]); |
|
91 |
|
|
92 |
if (!(nssym = NSLookupSymbolInModule (module, init_fun))) { |
if (!(nssym = NSLookupSymbolInModule (module, init_fun))) { |
93 |
sfasl_error ("cannot retrieve entry point symbol in bundle\n"); |
sfasl_error ("cannot retrieve entry point symbol in bundle\n"); |
94 |
} |
} |
95 |
} |
} |
96 |
|
|
97 |
if (!(fptr = (int (*) ()) NSAddressOfSymbol(nssym))) { |
if (!(fptr = (int (*) ()) NSAddressOfSymbol (nssym))) { |
98 |
sfasl_error ("cannot retrieve entry point address\n"); |
sfasl_error ("cannot retrieve entry point address\n"); |
99 |
} |
} |
100 |
|
|
101 |
if (!_dyld_present ()) { |
for (n = _dyld_image_count () ; --n != (unsigned long) -1 ; ) |
102 |
sfasl_error ("how can _dyld_present return false at this point !?\n"); |
{ |
|
} |
|
|
|
|
|
image_count = _dyld_image_count (); |
|
|
|
|
|
for (n=0 ; n < image_count ; n++) { |
|
103 |
if (strstr (filename, _dyld_get_image_name (n))) |
if (strstr (filename, _dyld_get_image_name (n))) |
104 |
{ |
{ |
105 |
vmaddr_slide = _dyld_get_image_vmaddr_slide (n); |
struct mach_header *mh = _dyld_get_image_header (n); |
106 |
header = _dyld_get_image_header (n); |
struct load_command *lc = (struct load_command *) (mh+1); |
107 |
|
unsigned long i; |
108 |
lc = (struct load_command *) (header + 1); |
|
109 |
|
vmsize = 0; |
110 |
for (i=0 ; i < header->ncmds ; i++) { |
|
111 |
|
for (i=0 ; i < mh->ncmds ; i++) { |
112 |
if (lc->cmd == LC_SEGMENT) { |
if (lc->cmd == LC_SEGMENT) { |
113 |
vmsize += ((struct segment_command *) lc)->vmsize; |
if (base_addr == (unsigned long) -1) { |
114 |
|
base_addr = ((struct segment_command *) lc)->vmaddr; |
115 |
|
} |
116 |
|
vmsize += ((struct segment_command *) lc)->vmsize; |
117 |
} |
} |
118 |
lc = (struct load_command *) ((char *) lc + lc->cmdsize); |
lc = (struct load_command *) ((char *) lc + lc->cmdsize); |
119 |
} |
} |
120 |
|
|
121 |
|
vmaddr_slide = _dyld_get_image_vmaddr_slide (n); |
122 |
|
|
123 |
break; |
break; |
124 |
} |
} |
125 |
} |
} |
126 |
|
|
127 |
mark_region (vmaddr_slide, vmsize); |
if (base_addr != (unsigned long) -1) { |
128 |
|
mark_region (vmaddr_slide - base_addr, vmsize); |
129 |
|
} else { |
130 |
|
sfasl_error ("could not retrieve newly created bundle image\n"); |
131 |
|
} |
132 |
|
|
133 |
return (fptr); |
return (fptr); |
134 |
} |
} |
135 |
|
|
148 |
|
|
149 |
static int count = 0; |
static int count = 0; |
150 |
|
|
151 |
if (count == 0) count = time (0); |
static char ldfmt [] = "gcc -bind_at_load -bundle -bundle_loader %s -o %s %s"; |
152 |
|
|
153 |
|
char fmt [MAXPATHLEN]; |
154 |
|
|
155 |
|
extern int seek_to_end_ofile (FILE *); |
156 |
|
|
157 |
|
if (count == 0) { |
158 |
|
/* DEFVAR ("*MACOSX-LDCMD*",sSAmacosx_ldcmdA,LISP,make_simple_string(ldfmt),""); */ |
159 |
|
sSAmacosx_ldcmdA = make_special ("*MACOSX-LDCMD*", make_simple_string (ldfmt)); |
160 |
|
count = time (0); |
161 |
|
} |
162 |
|
|
163 |
coerce_to_filename (truename (faslfile), filename); |
coerce_to_filename (truename (faslfile), filename); |
164 |
|
|
165 |
snprintf (tmpfile, sizeof(tmpfile), "/tmp/ufas%dx.so", count++); |
snprintf (tmpfile, sizeof (tmpfile), "/tmp/ufas%dx.so", count++); |
166 |
|
|
167 |
mkstemp (tmpfile); |
mkstemp (tmpfile); |
168 |
symlink (filename, tmpfile); |
symlink (filename, tmpfile); |
169 |
|
|
170 |
faslstream = open_stream (faslfile, smm_input, Cnil, sKerror); |
faslstream = open_stream (faslfile, smm_input, Cnil, sKerror); |
171 |
|
|
172 |
/* we could do a -flat_namespace build */ |
/* I guess the program will crash if a dumped image is ever dynamically relinked against |
173 |
snprintf (cmd, sizeof(cmd), |
a version of a shared library different from the one used at the time the bundle got |
174 |
"gcc -bind_at_load -bundle -bundle_loader %s %s -o %s", kcl_self, filename, tmpfile); |
loaded (if the bundle makes reference to this shared library). To avoid this, we |
175 |
|
would need all external bundle calls to be indirected through the loader image stubs. */ |
176 |
|
|
177 |
|
coerce_to_filename (symbol_value (sSAmacosx_ldcmdA), fmt); |
178 |
|
|
179 |
|
snprintf (cmd, sizeof(cmd), fmt, kcl_self, tmpfile, filename); |
180 |
|
|
181 |
if (system (cmd) != 0) { |
if (system (cmd) != 0) { |
182 |
sfasl_error ("cannot execute command: `%s'\n", cmd); |
sfasl_error ("cannot execute command `%s'\n", cmd); |
183 |
} |
} |
184 |
|
|
185 |
fptr = prepare_bundle (faslfile, tmpfile); |
fptr = prepare_bundle (faslfile, tmpfile); |
186 |
|
|
187 |
seek_to_end_ofile (faslstream->sm.sm_fp); |
if (seek_to_end_ofile (faslstream->sm.sm_fp) != 1) { |
188 |
|
sfasl_error ("error seeking to end of object file"); |
189 |
|
} |
190 |
|
|
191 |
data = read_fasl_vector (faslstream); |
data = read_fasl_vector (faslstream); |
192 |
|
|
193 |
close_stream (faslstream); |
close_stream (faslstream); |
194 |
|
|
195 |
memory = alloc_object(t_cfdata); |
memory = alloc_object (t_cfdata); |
196 |
memory->cfd.cfd_self = NULL; |
memory->cfd.cfd_self = NULL; |
197 |
memory->cfd.cfd_start = NULL; |
memory->cfd.cfd_start = NULL; |
198 |
memory->cfd.cfd_size = 0; |
memory->cfd.cfd_size = 0; |
199 |
|
|
200 |
if (symbol_value (sLAload_verboseA) != Cnil) |
if (symbol_value (sLAload_verboseA) != Cnil) |
201 |
printf (" start address (dynamic) %p ",fptr); |
printf (" start address (dynamic) %p ", fptr); |
202 |
|
|
203 |
call_init (0, memory, data, fptr); |
call_init (0, memory, data, fptr); |
204 |
|
|