Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/modules.c

Source at commit 680 created 13 years 4 months ago.
By meklort, Module loader update: Read in special librayr ordinal values correctly. Now uses the values to ignore certain bind information when unneded
1/*
2 * Copyright 2010 Evan Lojewski. All rights reserved.
3 *
4 * TODO: Zero out bss if needed
5 */
6
7#include "boot.h"
8#include "bootstruct.h"
9#include "modules.h"
10
11#ifndef DEBUG_MODULES
12#define DEBUG_MODULES 0
13#endif
14
15#if DEBUG_MODULES
16#define DBG(x...)printf(x); getc()
17#else
18#define DBG(x...)
19#endif
20
21// NOTE: Global so that modules can link with this
22unsigned long long textAddress = 0;
23unsigned long long textSection = 0;
24
25void* symbols_module_start = (void*)0xFFFFFFFF;// This will be modified post compile
26
27/** Internal symbols, however there are accessor methods **/
28moduleHook_t* moduleCallbacks = NULL;
29moduleList_t* loadedModules = NULL;
30symbolList_t* moduleSymbols = NULL;
31unsigned int (*lookup_symbol)(const char*) = NULL;
32
33
34
35
36
37#if DEBUG_MODULES
38void print_hook_list()
39{
40printf("---Hook Table---\n");
41
42moduleHook_t* hooks = moduleCallbacks;
43while(hooks)
44{
45printf("Hook: %s\n", hooks->name);
46hooks = hooks->next;
47}
48}
49#endif
50
51/*
52 * Initialize the module system by loading the Symbols.dylib module.
53 * Once loaded, locate the _lookup_symbol function so that internal
54 * symbols can be resolved.
55 */
56int init_module_system()
57{
58void (*module_start)(void) = NULL;
59char* module_data = symbols_module_start + BOOT2_ADDR;
60// Intialize module system
61if(symbols_module_start == (void*)0xFFFFFFFF)
62{
63DBG("Module system not compiled in\n");
64load_module(SYMBOLS_MODULE);
65
66lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);
67
68if((UInt32)lookup_symbol != 0xFFFFFFFF)
69{
70return 1;
71}
72
73return 0;
74}
75
76module_start = parse_mach(module_data, &load_module, &add_symbol);
77
78if(module_start && module_start != (void*)0xFFFFFFFF)
79{
80// Notify the system that it was laoded
81module_loaded(SYMBOLS_MODULE /*moduleName, moduleVersion, moduleCompat*/);
82(*module_start)();// Start the module
83DBG("Module %s Loaded.\n", SYMBOLS_MODULE);
84
85lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);
86
87if((UInt32)lookup_symbol != 0xFFFFFFFF)
88{
89return 1;
90}
91}
92else {
93// The module does not have a valid start function
94printf("Unable to start %s\n", SYMBOLS_MODULE);
95getc();
96}
97return 0;
98}
99
100
101/*
102 * Load all modules in the /Extra/modules/ directory
103 * Module depencdies will be loaded first
104 * MOdules will only be loaded once. When loaded a module must
105 * setup apropriete function calls and hooks as required.
106 * NOTE: To ensure a module loads after another you may
107 * link one module with the other. For dyld to allow this, you must
108 * reference at least one symbol within the module.
109 */
110void load_all_modules()
111{
112char* name;
113long flags;
114long time;
115struct dirstuff* moduleDir = opendir("/Extra/modules/");
116while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
117{
118if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)
119{
120char* tmp = malloc(strlen(name) + 1);
121strcpy(tmp, name);
122
123DBG("Attempting to load %s\n", tmp);
124if(!load_module(tmp))
125{
126// failed to load
127// free(tmp);
128}
129}
130else
131{
132DBG("Ignoring %s\n", name);
133}
134
135}
136}
137
138
139/*
140 * Load a module file in /Extra/modules
141 * TODO: verify version number of module
142 */
143int load_module(char* module)
144{
145void (*module_start)(void) = NULL;
146
147
148// Check to see if the module has already been loaded
149if(is_module_loaded(module))
150{
151// NOTE: Symbols.dylib tries to load twice, this catches it as well
152// as when a module links with an already loaded module
153DBG("Module %s already loaded\n", module);
154return 1;
155}
156
157char modString[128];
158int fh = -1;
159sprintf(modString, "/Extra/modules/%s", module);
160fh = open(modString, 0);
161if(fh < 0)
162{
163printf("Unable to locate module %s\n", modString);
164getc();
165return 0;
166}
167
168unsigned int moduleSize = file_size(fh);
169char* module_base = (char*) malloc(moduleSize);
170if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)
171{
172
173DBG("Module %s read in.\n", modString);
174
175// Module loaded into memory, parse it
176module_start = parse_mach(module_base, &load_module, &add_symbol);
177
178if(module_start && module_start != (void*)0xFFFFFFFF)
179{
180// Notify the system that it was laoded
181module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);
182(*module_start)();// Start the module
183DBG("Module %s Loaded.\n", module);
184}
185else {
186// The module does not have a valid start function
187printf("Unable to start %s\n", module);
188getc();
189}
190}
191else
192{
193DBG("Unable to read in module %s\n.", module);
194getc();
195}
196close(fh);
197return 1;
198}
199
200/*
201 *execute_hook( const char* name )
202 *name - Name of the module hook
203 *If any callbacks have been registered for this hook
204 *they will be executed now in the same order that the
205 *hooks were added.
206 */
207int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
208{
209DBG("Attempting to execute hook '%s'\n", name);
210moduleHook_t* hooks = moduleCallbacks;
211
212while(hooks && strcmp(name, hooks->name) < 0)
213{
214//DBG("%s cmp %s = %d\n", name, hooks->name, strcmp(name, hooks->name));
215hooks = hooks->next;
216}
217
218if(hooks && strcmp(name, hooks->name) == 0)
219{
220// Loop through all callbacks for this module
221callbackList_t* callbacks = hooks->callbacks;
222
223while(callbacks)
224{
225DBG("Executing '%s' with callback 0x%X.\n", name, callbacks->callback);
226// Execute callback
227callbacks->callback(arg1, arg2, arg3, arg4);
228callbacks = callbacks->next;
229DBG("Hook '%s' callback executed, next is 0x%X.\n", name, callbacks);
230
231}
232DBG("Hook '%s' executed.\n", name);
233
234return 1;
235}
236else
237{
238DBG("No callbacks for '%s' hook.\n", name);
239
240// Callbaack for this module doesn't exist;
241//verbose("Unable execute hook '%s', no callbacks registered.\n", name);
242//pause();
243return 0;
244}
245}
246
247
248
249/*
250 *register_hook_callback( const char* name, void(*callback)())
251 *name - Name of the module hook to attach to.
252 *callbacks - The funciton pointer that will be called when the
253 *hook is executed. When registering a new callback name, the callback is added sorted.
254 *NOTE: the hooks take four void* arguments.
255 *TODO: refactor
256 */
257void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
258{
259DBG("Adding callback for '%s' hook.\n", name);
260
261moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
262if(!moduleCallbacks)
263{
264newHook->next = moduleCallbacks;
265moduleCallbacks = newHook;
266
267newHook->name = name;
268newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));
269newHook->callbacks->callback = callback;
270newHook->callbacks->next = NULL;
271}
272else
273{
274moduleHook_t* hooks = moduleCallbacks;
275
276while(hooks->next && strcmp(name, hooks->next->name) < 0)
277{
278hooks = hooks->next;
279}
280
281if(!hooks->next)
282{
283// Appent to the end
284newHook->next = NULL;
285hooks->next = newHook;
286newHook->name = name;
287newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));
288newHook->callbacks->callback = callback;
289newHook->callbacks->next = NULL;
290
291
292}
293else if(strcmp(name, hooks->next->name) == 0)
294{
295// We found the hook
296// Hook alreday exists, add a callback to this hook
297callbackList_t* callbacks = hooks->next->callbacks;
298while(callbacks->next != NULL)
299{
300callbacks = callbacks->next;
301}
302// Add new entry to end of hook list.
303callbacks->next = (callbackList_t*)malloc(sizeof(callbackList_t));
304callbacks = callbacks->next;
305callbacks->next = NULL;
306callbacks->callback = callback;
307}
308else
309{
310// We are too far beyond the hook
311newHook->next = hooks->next;
312hooks->next = newHook;
313newHook->name = name;
314newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));
315newHook->callbacks->callback = callback;
316newHook->callbacks->next = NULL;
317
318}
319}
320#if DEBUG_MODULES
321print_hook_list();
322getc();
323#endif
324
325}
326
327
328/*
329 * Parse through a macho module. The module will be rebased and binded
330 * as specified in the macho header. If the module is sucessfuly laoded
331 * the module iinit address will be returned.
332 * NOTE; all dependecies will be loaded before this module is started
333 * NOTE: If the module is unable to load ot completeion, the modules
334 * symbols will still be available (TODO: fix this). This should not
335 * happen as all dependencies are verified before the sybols are read in.
336 */
337void* parse_mach(void* binary, int(*dylib_loader)(char*), long long(*symbol_handler)(char*, long long, char))// TODO: add param to specify valid archs
338{
339char is64 = false;
340void (*module_start)(void) = NULL;
341
342// Module info
343/*char* moduleName = NULL;
344UInt32 moduleVersion = 0;
345UInt32 moduleCompat = 0;
346*/
347// TODO convert all of the structs to a union
348struct load_command *loadCommand = NULL;
349struct dylib_command* dylibCommand = NULL;
350struct dyld_info_command* dyldInfoCommand = NULL;
351
352struct symtab_command* symtabCommand = NULL;
353struct segment_command *segCommand = NULL;
354struct segment_command_64 *segCommand64 = NULL;
355
356//struct dysymtab_command* dysymtabCommand = NULL;
357UInt32 binaryIndex = 0;
358UInt16 cmd = 0;
359
360// Parse through the load commands
361if(((struct mach_header*)binary)->magic == MH_MAGIC)
362{
363is64 = false;
364binaryIndex += sizeof(struct mach_header);
365}
366else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
367{
368// NOTE: modules cannot be 64bit...
369is64 = true;
370binaryIndex += sizeof(struct mach_header_64);
371}
372else
373{
374printf("Invalid mach magic\n");
375getc();
376return NULL;
377}
378
379
380
381/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
382{
383printf("Module is not a dylib. Unable to load.\n");
384getc();
385return NULL; // Module is in the incorrect format
386}*/
387
388while(cmd < ((struct mach_header*)binary)->ncmds)
389{
390cmd++;
391
392loadCommand = binary + binaryIndex;
393UInt32 cmdSize = loadCommand->cmdsize;
394
395
396switch ((loadCommand->cmd & 0x7FFFFFFF))
397{
398// TODO: sepeare function to handel appropriate sections
399case LC_SYMTAB:
400symtabCommand = binary + binaryIndex;
401break;
402
403case LC_SEGMENT: // 32bit macho
404segCommand = binary + binaryIndex;
405
406//printf("Segment name is %s\n", segCommand->segname);
407
408if(strcmp("__TEXT", segCommand->segname) == 0)
409{
410UInt32 sectionIndex;
411
412sectionIndex = sizeof(struct segment_command);
413
414struct section *sect;
415
416while(sectionIndex < segCommand->cmdsize)
417{
418sect = binary + binaryIndex + sectionIndex;
419
420sectionIndex += sizeof(struct section);
421
422
423if(strcmp("__text", sect->sectname) == 0)
424{
425// __TEXT,__text found, save the offset and address for when looking for the calls.
426textSection = sect->offset;
427textAddress = sect->addr;
428break;
429}
430}
431}
432else if(strcmp("__DATA", segCommand->segname) == 0)
433{
434UInt32 sectionIndex;
435
436sectionIndex = sizeof(struct segment_command);
437
438struct section *sect;
439
440while(sectionIndex < segCommand->cmdsize)
441{
442sect = binary + binaryIndex + sectionIndex;
443
444sectionIndex += sizeof(struct section);
445
446
447if(strcmp("__bss", sect->sectname) == 0)
448{
449// __TEXT,__text found, save the offset and address for when looking for the calls.
450//printf("__DATA,__bss found.\n"); getc();
451break;
452}
453}
454
455}
456
457break;
458case LC_SEGMENT_64:// 64bit macho's
459segCommand64 = binary + binaryIndex;
460
461//printf("Segment name is %s\n", segCommand->segname);
462
463if(strcmp("__TEXT", segCommand64->segname) == 0)
464{
465UInt32 sectionIndex;
466
467sectionIndex = sizeof(struct segment_command_64);
468
469struct section_64 *sect;
470
471while(sectionIndex < segCommand64->cmdsize)
472{
473sect = binary + binaryIndex + sectionIndex;
474
475sectionIndex += sizeof(struct section_64);
476
477
478if(strcmp("__text", sect->sectname) == 0)
479{
480// __TEXT,__text found, save the offset and address for when looking for the calls.
481textSection = sect->offset;
482textAddress = sect->addr;
483
484break;
485}
486}
487}
488else if(strcmp("__DATA", segCommand->segname) == 0)
489{
490UInt32 sectionIndex;
491
492sectionIndex = sizeof(struct segment_command_64);
493
494struct section_64 *sect;
495
496while(sectionIndex < segCommand->cmdsize)
497{
498sect = binary + binaryIndex + sectionIndex;
499
500sectionIndex += sizeof(struct section);
501
502
503if(strcmp("__bss", sect->sectname) == 0)
504{
505// __TEXT,__text found, save the offset and address for when looking for the calls.
506//printf("__DATA,__bss found.\n"); getc();
507break;
508}
509}
510
511}
512
513
514break;
515
516case LC_DYSYMTAB:
517break;
518
519case LC_LOAD_DYLIB:
520case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
521dylibCommand = binary + binaryIndex;
522char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
523// TODO: verify version
524// =dylibCommand->dylib.current_version;
525// =dylibCommand->dylib.compatibility_version;
526if(dylib_loader)
527{
528char* name = malloc(strlen(module) + strlen(".dylib") + 1);
529sprintf(name, "%s.dylib", module);
530
531if (!dylib_loader(name))
532{
533free(name);
534// Unable to load dependancy
535//return NULL;
536}
537}
538
539break;
540
541case LC_ID_DYLIB:
542dylibCommand = binary + binaryIndex;
543/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
544moduleVersion =dylibCommand->dylib.current_version;
545moduleCompat =dylibCommand->dylib.compatibility_version;
546 */
547break;
548
549case LC_DYLD_INFO:
550// Bind and rebase info is stored here
551dyldInfoCommand = binary + binaryIndex;
552break;
553
554case LC_UUID:
555break;
556
557case LC_UNIXTHREAD:
558break;
559
560default:
561DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
562break;
563
564}
565
566binaryIndex += cmdSize;
567}
568//if(!moduleName) return NULL;
569
570
571// bind_macho uses the symbols.
572module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
573
574// Rebase the module before binding it.
575if(dyldInfoCommand && dyldInfoCommand->rebase_off)
576{
577rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
578}
579
580if(dyldInfoCommand && dyldInfoCommand->bind_off)
581{
582bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
583}
584
585if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
586{
587// NOTE: this currently should never happen.
588bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
589}
590
591if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
592{
593// NOTE: we are binding the lazy pointers as a module is laoded,
594// This should be changed to bind when a symbol is referened at runtime instead.
595bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
596}
597
598return module_start;
599
600}
601
602
603// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
604void rebase_macho(void* base, char* rebase_stream, UInt32 size)
605{
606rebase_stream += (UInt32)base;
607
608UInt8 immediate = 0;
609UInt8 opcode = 0;
610UInt8 type = 0;
611
612UInt32 segmentAddress = 0;
613
614
615
616UInt32 tmp = 0;
617UInt32 tmp2 = 0;
618UInt8 bits = 0;
619int index = 0;
620
621//int done = 0;
622unsigned int i = 0;
623
624while(/*!done &&*/ i < size)
625{
626immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
627opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
628
629
630switch(opcode)
631{
632case REBASE_OPCODE_DONE:
633// Rebase complete.
634//done = 1;
635default:
636break;
637
638
639case REBASE_OPCODE_SET_TYPE_IMM:
640// Set rebase type (pointer, absolute32, pcrel32)
641//DBG("Rebase type = 0x%X\n", immediate);
642type = immediate;
643break;
644
645
646case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
647// Locate address to begin rebasing
648segmentAddress = 0;
649
650struct segment_command* segCommand = NULL; // NOTE: 32bit only
651
652unsigned int binIndex = 0;
653index = 0;
654do
655{
656segCommand = base + sizeof(struct mach_header) + binIndex;
657
658
659binIndex += segCommand->cmdsize;
660index++;
661}
662while(index <= immediate);
663
664
665segmentAddress = segCommand->fileoff;
666
667tmp = 0;
668bits = 0;
669do
670{
671tmp |= (rebase_stream[++i] & 0x7f) << bits;
672bits += 7;
673}
674while(rebase_stream[i] & 0x80);
675
676segmentAddress += tmp;
677break;
678
679
680case REBASE_OPCODE_ADD_ADDR_ULEB:
681// Add value to rebase address
682tmp = 0;
683bits = 0;
684do
685{
686tmp <<= bits;
687tmp |= rebase_stream[++i] & 0x7f;
688bits += 7;
689}
690while(rebase_stream[i] & 0x80);
691
692segmentAddress +=tmp;
693break;
694
695case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
696segmentAddress += immediate * sizeof(void*);
697break;
698
699
700case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
701index = 0;
702for (index = 0; index < immediate; ++index) {
703rebase_location(base + segmentAddress, (char*)base, type);
704segmentAddress += sizeof(void*);
705}
706break;
707
708
709case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
710tmp = 0;
711bits = 0;
712do
713{
714tmp |= (rebase_stream[++i] & 0x7f) << bits;
715bits += 7;
716}
717while(rebase_stream[i] & 0x80);
718
719index = 0;
720for (index = 0; index < tmp; ++index) {
721//DBG("\tRebasing 0x%X\n", segmentAddress);
722rebase_location(base + segmentAddress, (char*)base, type);
723segmentAddress += sizeof(void*);
724}
725break;
726
727case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
728tmp = 0;
729bits = 0;
730do
731{
732tmp |= (rebase_stream[++i] & 0x7f) << bits;
733bits += 7;
734}
735while(rebase_stream[i] & 0x80);
736
737rebase_location(base + segmentAddress, (char*)base, type);
738
739segmentAddress += tmp + sizeof(void*);
740break;
741
742case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
743tmp = 0;
744bits = 0;
745do
746{
747tmp |= (rebase_stream[++i] & 0x7f) << bits;
748bits += 7;
749}
750while(rebase_stream[i] & 0x80);
751
752
753tmp2 = 0;
754bits = 0;
755do
756{
757tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
758bits += 7;
759}
760while(rebase_stream[i] & 0x80);
761
762index = 0;
763for (index = 0; index < tmp; ++index) {
764
765rebase_location(base + segmentAddress, (char*)base, type);
766
767segmentAddress += tmp2 + sizeof(void*);
768}
769break;
770}
771i++;
772}
773}
774
775// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
776// NOTE: this uses 32bit values, and not 64bit values.
777// There is apossibility that this could cause issues,
778// however the macho file is 32 bit, so it shouldn't matter too much
779void bind_macho(void* base, char* bind_stream, UInt32 size)
780{
781bind_stream += (UInt32)base;
782
783UInt8 immediate = 0;
784UInt8 opcode = 0;
785UInt8 type = 0;
786
787UInt32 segmentAddress = 0;
788
789UInt32 address = 0;
790
791SInt32 addend = 0;// TODO: handle this
792SInt32 libraryOrdinal = 0;
793
794const char* symbolName = NULL;
795UInt8 symboFlags = 0;
796UInt32 symbolAddr = 0xFFFFFFFF;
797
798// Temperary variables
799UInt8 bits = 0;
800UInt32 tmp = 0;
801UInt32 tmp2 = 0;
802
803UInt32 index = 0;
804//int done = 0;
805unsigned int i = 0;
806
807while(/*!done &&*/ i < size)
808{
809immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
810opcode = bind_stream[i] & BIND_OPCODE_MASK;
811
812
813switch(opcode)
814{
815case BIND_OPCODE_DONE:
816//done = 1;
817default:
818break;
819
820case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
821libraryOrdinal = immediate;
822//printf("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
823break;
824
825case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
826libraryOrdinal = 0;
827bits = 0;
828do
829{
830libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
831bits += 7;
832}
833while(bind_stream[i] & 0x80);
834
835//printf("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
836
837break;
838
839case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
840// NOTE: this is wrong, fortunately we don't use it
841libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;
842//printf("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
843
844break;
845
846case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
847symboFlags = immediate;
848symbolName = (char*)&bind_stream[++i];
849i += strlen((char*)&bind_stream[i]);
850//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
851
852symbolAddr = lookup_all_symbols(symbolName);
853
854break;
855
856case BIND_OPCODE_SET_TYPE_IMM:
857// Set bind type (pointer, absolute32, pcrel32)
858type = immediate;
859//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
860
861break;
862
863case BIND_OPCODE_SET_ADDEND_SLEB:
864addend = 0;
865bits = 0;
866do
867{
868addend |= (bind_stream[++i] & 0x7f) << bits;
869bits += 7;
870}
871while(bind_stream[i] & 0x80);
872
873if(!(bind_stream[i-1] & 0x40)) addend *= -1;
874
875//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
876break;
877
878case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
879segmentAddress = 0;
880
881// Locate address
882struct segment_command* segCommand = NULL;// NOTE: 32bit only
883
884unsigned int binIndex = 0;
885index = 0;
886do
887{
888segCommand = base + sizeof(struct mach_header) + binIndex;
889binIndex += segCommand->cmdsize;
890index++;
891}
892while(index <= immediate);
893
894segmentAddress = segCommand->fileoff;
895
896// Read in offset
897tmp = 0;
898bits = 0;
899do
900{
901tmp |= (bind_stream[++i] & 0x7f) << bits;
902bits += 7;
903}
904while(bind_stream[i] & 0x80);
905
906segmentAddress += tmp;
907
908//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
909break;
910
911case BIND_OPCODE_ADD_ADDR_ULEB:
912// Read in offset
913tmp = 0;
914bits = 0;
915do
916{
917tmp |= (bind_stream[++i] & 0x7f) << bits;
918bits += 7;
919}
920while(bind_stream[i] & 0x80);
921
922segmentAddress += tmp;
923//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
924break;
925
926case BIND_OPCODE_DO_BIND:
927//DBG("BIND_OPCODE_DO_BIND\n");
928if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)
929{
930// HACK(ish)
931// Internal symbol, don't bind
932}
933else
934{
935//printf("Binding symbol %s, libraryOrdinal = %d, symboFlags = %d, type = %d\n", symbolName, libraryOrdinal, symboFlags, type);
936
937if(symbolAddr != 0xFFFFFFFF)
938{
939address = segmentAddress + (UInt32)base;
940
941bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
942}
943else
944{
945printf("Unable to bind symbol %s, libraryOrdinal = %d, symboFlags = %d, type = %d\n", symbolName, libraryOrdinal, symboFlags, type);
946getc();
947}
948}
949
950segmentAddress += sizeof(void*);
951break;
952
953case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
954//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
955
956
957// Read in offset
958tmp = 0;
959bits = 0;
960do
961{
962tmp |= (bind_stream[++i] & 0x7f) << bits;
963bits += 7;
964}
965while(bind_stream[i] & 0x80);
966
967
968if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)
969{
970// Internal symbol, don't bind
971}
972else
973{
974if(symbolAddr != 0xFFFFFFFF)
975{
976address = segmentAddress + (UInt32)base;
977
978bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
979}
980else
981{
982printf("Unable to bind symbol %s\n", symbolName);
983getc();
984}
985}
986segmentAddress += tmp + sizeof(void*);
987
988
989break;
990
991case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
992//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
993if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)
994{
995// Internal symbol, don't bind
996}
997else
998{
999if(symbolAddr != 0xFFFFFFFF)
1000{
1001address = segmentAddress + (UInt32)base;
1002
1003bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1004}
1005else
1006{
1007printf("Unable to bind symbol %s\n", symbolName);
1008getc();
1009}
1010}
1011segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
1012
1013
1014break;
1015
1016case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1017
1018tmp = 0;
1019bits = 0;
1020do
1021{
1022tmp |= (bind_stream[++i] & 0x7f) << bits;
1023bits += 7;
1024}
1025while(bind_stream[i] & 0x80);
1026
1027
1028tmp2 = 0;
1029bits = 0;
1030do
1031{
1032tmp2 |= (bind_stream[++i] & 0x7f) << bits;
1033bits += 7;
1034}
1035while(bind_stream[i] & 0x80);
1036
1037
1038//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
1039
1040
1041if(symbolAddr != 0xFFFFFFFF)
1042{
1043for(index = 0; index < tmp; index++)
1044{
1045
1046address = segmentAddress + (UInt32)base;
1047if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)
1048{
1049// Internal symbol, don't bind
1050}
1051else
1052{
1053
1054bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1055}
1056segmentAddress += tmp2 + sizeof(void*);
1057}
1058}
1059else
1060{
1061if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)
1062{
1063// Internal symbol, don't bind
1064}
1065else
1066{
1067printf("Unable to bind symbol %s\n", symbolName);
1068getc();
1069}
1070}
1071
1072
1073break;
1074
1075}
1076i++;
1077}
1078}
1079
1080inline void rebase_location(UInt32* location, char* base, int type)
1081{
1082switch(type)
1083{
1084case REBASE_TYPE_POINTER:
1085case REBASE_TYPE_TEXT_ABSOLUTE32:
1086*location += (UInt32)base;
1087break;
1088
1089default:
1090break;
1091}
1092}
1093
1094inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
1095{
1096// do actual update
1097char* newValue = value + addend;
1098
1099switch (type) {
1100case BIND_TYPE_POINTER:
1101case BIND_TYPE_TEXT_ABSOLUTE32:
1102break;
1103
1104case BIND_TYPE_TEXT_PCREL32:
1105newValue -= ((UInt32)location + 4);
1106
1107break;
1108default:
1109return;
1110}
1111
1112*location = (UInt32)newValue;
1113}
1114
1115
1116/*
1117 * add_symbol
1118 * This function adds a symbol from a module to the list of known symbols
1119 * possibly change to a pointer and add this to the Symbol module so that it can
1120 * adjust it's internal symbol list (sort) to optimize locating new symbols
1121 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
1122 */
1123long long add_symbol(char* symbol, long long addr, char is64)
1124{
1125if(is64) return 0xFFFFFFFF; // Fixme
1126
1127// This only can handle 32bit symbols
1128symbolList_t* entry;
1129//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
1130
1131if(!moduleSymbols)
1132{
1133moduleSymbols = entry = malloc(sizeof(symbolList_t));
1134
1135}
1136else
1137{
1138entry = moduleSymbols;
1139while(entry->next)
1140{
1141entry = entry->next;
1142}
1143
1144entry->next = malloc(sizeof(symbolList_t));
1145entry = entry->next;
1146}
1147
1148entry->next = NULL;
1149entry->addr = (UInt32)addr;
1150entry->symbol = symbol;
1151
1152if(strcmp(symbol, "start") == 0)
1153{
1154return addr;
1155}
1156else
1157{
1158return 0xFFFFFFFF; // fixme
1159}
1160}
1161
1162
1163/*
1164 * print out the information about the loaded module
1165
1166 */
1167void module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)
1168{
1169// TODO: insert sorted
1170moduleList_t* new_entry = malloc(sizeof(moduleList_t));
1171
1172new_entry->next = loadedModules;
1173loadedModules = new_entry;
1174
1175new_entry->module = (char*)name;
1176new_entry->version = 0; //version;
1177new_entry->compat = 0; //compat;
1178}
1179
1180int is_module_loaded(const char* name)
1181{
1182// todo sorted search
1183moduleList_t* entry = loadedModules;
1184while(entry)
1185{
1186DBG("Comparing %s with %s\n", name, entry->module);
1187if(strcmp(entry->module, name) == 0)
1188{
1189DBG("Located module %s\n", name);
1190return 1;
1191}
1192else
1193{
1194entry = entry->next;
1195}
1196
1197}
1198DBG("Module %s not found\n", name);
1199
1200return 0;
1201}
1202
1203// Look for symbols using the Smbols moduel function.
1204// If non are found, look through the list of module symbols
1205unsigned int lookup_all_symbols(const char* name)
1206{
1207unsigned int addr = 0xFFFFFFFF;
1208symbolList_t* entry = moduleSymbols;
1209while(entry)
1210{
1211if(strcmp(entry->symbol, name) == 0)
1212{
1213//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1214return entry->addr;
1215}
1216else
1217{
1218entry = entry->next;
1219}
1220
1221}
1222
1223if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1224{
1225addr = lookup_symbol(name);
1226if(addr != 0xFFFFFFFF)
1227{
1228//DBG("Internal symbol %s located at 0x%X\n", name, addr);
1229return addr;
1230}
1231}
1232
1233
1234#if DEBUG_MODULES
1235verbose("Unable to locate symbol %s\n", name);
1236getc();
1237#endif
1238
1239return 0xFFFFFFFF;
1240}
1241
1242
1243/*
1244 * parse the symbol table
1245 * Lookup any undefined symbols
1246 */
1247
1248unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
1249{
1250// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not
1251//subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)
1252
1253unsigned int module_start = 0xFFFFFFFF;
1254
1255UInt32 symbolIndex = 0;
1256char* symbolString = base + (char*)symtabCommand->stroff;
1257//char* symbolTable = base + symtabCommand->symoff;
1258if(!is64)
1259{
1260struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1261while(symbolIndex < symtabCommand->nsyms)
1262{
1263// If the symbol is exported by this module
1264if(symbolEntry->n_value &&
1265 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1266{
1267
1268// Module start located. Start is an alias so don't register it
1269module_start = base + symbolEntry->n_value;
1270}
1271
1272symbolEntry++;
1273symbolIndex++;// TODO remove
1274}
1275}
1276else
1277{
1278struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1279// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1280while(symbolIndex < symtabCommand->nsyms)
1281{
1282
1283
1284// If the symbol is exported by this module
1285if(symbolEntry->n_value &&
1286 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1287{
1288
1289// Module start located. Start is an alias so don't register it
1290module_start = base + symbolEntry->n_value;
1291}
1292
1293symbolEntry++;
1294symbolIndex++;// TODO remove
1295}
1296}
1297
1298return module_start;
1299
1300}
1301
1302
1303/*
1304 * Locate the symbol for an already loaded function and modify the beginning of
1305 * the function to jump directly to the new one
1306 * example: replace_function("_HelloWorld_start", &replacement_start);
1307 */
1308int replace_function(const char* symbol, void* newAddress)
1309{
1310UInt32* jumpPointer = malloc(sizeof(UInt32*));
1311// TODO: look into using the next four bytes of the function instead
1312// Most functions should support this, as they probably will be at
1313// least 10 bytes long, but you never know, this is sligtly safer as
1314// function can be as small as 6 bytes.
1315UInt32 addr = lookup_all_symbols(symbol);
1316
1317char* binary = (char*)addr;
1318if(addr != 0xFFFFFFFF)
1319{
1320DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);
1321*binary++ = 0xFF;// Jump
1322*binary++ = 0x25;// Long Jump
1323*((UInt32*)binary) = (UInt32)jumpPointer;
1324
1325*jumpPointer = (UInt32)newAddress;
1326
1327return 1;
1328}
1329else
1330{
1331return 0;
1332}
1333
1334}
1335
1336void dyld_stub_binder()
1337{
1338// TODO: actualy impliment this function (asm)
1339stop("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");
1340}

Archive Download this file

Revision: 680