Home | History | Annotate | Download | only in mach_override
      1 // mach_override.c semver:1.2.0
      2 //   Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
      3 //   Some rights reserved: http://opensource.org/licenses/mit
      4 //   https://github.com/rentzsch/mach_override
      5 
      6 #include "mach_override.h"
      7 #if defined(__i386__) || defined(__x86_64__)
      8 #include "udis86.h"
      9 #endif
     10 
     11 #include <mach-o/dyld.h>
     12 #include <mach/mach_host.h>
     13 #include <mach/mach_init.h>
     14 #include <mach/vm_map.h>
     15 #include <mach/vm_statistics.h>
     16 #include <sys/mman.h>
     17 
     18 #include <CoreServices/CoreServices.h>
     19 
     20 /**************************
     21 *
     22 *	Constants
     23 *
     24 **************************/
     25 #pragma mark	-
     26 #pragma mark	(Constants)
     27 
     28 #if defined(__ppc__) || defined(__POWERPC__)
     29 
     30 long kIslandTemplate[] = {
     31 	0x9001FFFC,	//	stw		r0,-4(SP)
     32 	0x3C00DEAD,	//	lis		r0,0xDEAD
     33 	0x6000BEEF,	//	ori		r0,r0,0xBEEF
     34 	0x7C0903A6,	//	mtctr	r0
     35 	0x8001FFFC,	//	lwz		r0,-4(SP)
     36 	0x60000000,	//	nop		; optionally replaced
     37 	0x4E800420 	//	bctr
     38 };
     39 
     40 #define kAddressHi			3
     41 #define kAddressLo			5
     42 #define kInstructionHi		10
     43 #define kInstructionLo		11
     44 
     45 #elif defined(__i386__)
     46 
     47 #define kOriginalInstructionsSize 16
     48 
     49 char kIslandTemplate[] = {
     50 	// kOriginalInstructionsSize nop instructions so that we
     51 	// should have enough space to host original instructions
     52 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     53 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     54 	// Now the real jump instruction
     55 	0xE9, 0xEF, 0xBE, 0xAD, 0xDE
     56 };
     57 
     58 #define kInstructions	0
     59 #define kJumpAddress    kInstructions + kOriginalInstructionsSize + 1
     60 #elif defined(__x86_64__)
     61 
     62 #define kOriginalInstructionsSize 32
     63 
     64 #define kJumpAddress    kOriginalInstructionsSize + 6
     65 
     66 char kIslandTemplate[] = {
     67 	// kOriginalInstructionsSize nop instructions so that we
     68 	// should have enough space to host original instructions
     69 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     70 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     71 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     72 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     73 	// Now the real jump instruction
     74 	0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
     75         0x00, 0x00, 0x00, 0x00,
     76         0x00, 0x00, 0x00, 0x00
     77 };
     78 
     79 #endif
     80 
     81 #define	kAllocateHigh		1
     82 #define	kAllocateNormal		0
     83 
     84 /**************************
     85 *
     86 *	Data Types
     87 *
     88 **************************/
     89 #pragma mark	-
     90 #pragma mark	(Data Types)
     91 
     92 typedef	struct	{
     93 	char	instructions[sizeof(kIslandTemplate)];
     94 	int		allocatedHigh;
     95 }	BranchIsland;
     96 
     97 /**************************
     98 *
     99 *	Funky Protos
    100 *
    101 **************************/
    102 #pragma mark	-
    103 #pragma mark	(Funky Protos)
    104 
    105 	mach_error_t
    106 allocateBranchIsland(
    107 		BranchIsland	**island,
    108 		int				allocateHigh,
    109 		void *originalFunctionAddress);
    110 
    111 	mach_error_t
    112 freeBranchIsland(
    113 		BranchIsland	*island );
    114 
    115 #if defined(__ppc__) || defined(__POWERPC__)
    116 	mach_error_t
    117 setBranchIslandTarget(
    118 		BranchIsland	*island,
    119 		const void		*branchTo,
    120 		long			instruction );
    121 #endif
    122 
    123 #if defined(__i386__) || defined(__x86_64__)
    124 mach_error_t
    125 setBranchIslandTarget_i386(
    126 						   BranchIsland	*island,
    127 						   const void		*branchTo,
    128 						   char*			instructions );
    129 void
    130 atomic_mov64(
    131 		uint64_t *targetAddress,
    132 		uint64_t value );
    133 
    134 	static Boolean
    135 eatKnownInstructions(
    136 	unsigned char	*code,
    137 	uint64_t		*newInstruction,
    138 	int				*howManyEaten,
    139 	char			*originalInstructions,
    140 	int				*originalInstructionCount,
    141 	uint8_t			*originalInstructionSizes );
    142 
    143 	static void
    144 fixupInstructions(
    145     void		*originalFunction,
    146     void		*escapeIsland,
    147     void		*instructionsToFix,
    148 	int			instructionCount,
    149 	uint8_t		*instructionSizes );
    150 #endif
    151 
    152 /*******************************************************************************
    153 *
    154 *	Interface
    155 *
    156 *******************************************************************************/
    157 #pragma mark	-
    158 #pragma mark	(Interface)
    159 
    160 #if defined(__i386__) || defined(__x86_64__)
    161 mach_error_t makeIslandExecutable(void *address) {
    162 	mach_error_t err = err_none;
    163     vm_size_t pageSize;
    164     host_page_size( mach_host_self(), &pageSize );
    165     uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
    166     int e = err_none;
    167     e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ);
    168     e |= msync((void *)page, pageSize, MS_INVALIDATE );
    169     if (e) {
    170         err = err_cannot_override;
    171     }
    172     return err;
    173 }
    174 #endif
    175 
    176     mach_error_t
    177 mach_override_ptr(
    178 	void *originalFunctionAddress,
    179     const void *overrideFunctionAddress,
    180     void **originalFunctionReentryIsland )
    181 {
    182 	assert( originalFunctionAddress );
    183 	assert( overrideFunctionAddress );
    184 
    185 	// this addresses overriding such functions as AudioOutputUnitStart()
    186 	// test with modified DefaultOutputUnit project
    187 #if defined(__x86_64__)
    188     for(;;){
    189         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp qword near [rip+0x????????]
    190             originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
    191         else break;
    192     }
    193 #elif defined(__i386__)
    194     for(;;){
    195         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp *0x????????
    196             originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
    197         else break;
    198     }
    199 #endif
    200 
    201 	long	*originalFunctionPtr = (long*) originalFunctionAddress;
    202 	mach_error_t	err = err_none;
    203 
    204 #if defined(__ppc__) || defined(__POWERPC__)
    205 	//	Ensure first instruction isn't 'mfctr'.
    206 	#define	kMFCTRMask			0xfc1fffff
    207 	#define	kMFCTRInstruction	0x7c0903a6
    208 
    209 	long	originalInstruction = *originalFunctionPtr;
    210 	if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
    211 		err = err_cannot_override;
    212 #elif defined(__i386__) || defined(__x86_64__)
    213 	int eatenCount = 0;
    214 	int originalInstructionCount = 0;
    215 	char originalInstructions[kOriginalInstructionsSize];
    216 	uint8_t originalInstructionSizes[kOriginalInstructionsSize];
    217 	uint64_t jumpRelativeInstruction = 0; // JMP
    218 
    219 	Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
    220 										&jumpRelativeInstruction, &eatenCount,
    221 										originalInstructions, &originalInstructionCount,
    222 										originalInstructionSizes );
    223 	if (eatenCount > kOriginalInstructionsSize) {
    224 		//printf ("Too many instructions eaten\n");
    225 		overridePossible = false;
    226 	}
    227 	if (!overridePossible) err = err_cannot_override;
    228 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    229 #endif
    230 
    231 	//	Make the original function implementation writable.
    232 	if( !err ) {
    233 		err = vm_protect( mach_task_self(),
    234 				(vm_address_t) originalFunctionPtr, 8, false,
    235 				(VM_PROT_ALL | VM_PROT_COPY) );
    236 		if( err )
    237 			err = vm_protect( mach_task_self(),
    238 					(vm_address_t) originalFunctionPtr, 8, false,
    239 					(VM_PROT_DEFAULT | VM_PROT_COPY) );
    240 	}
    241 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    242 
    243 	//	Allocate and target the escape island to the overriding function.
    244 	BranchIsland	*escapeIsland = NULL;
    245 	if( !err )
    246 		err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress );
    247 		if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    248 
    249 
    250 #if defined(__ppc__) || defined(__POWERPC__)
    251 	if( !err )
    252 		err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
    253 
    254 	//	Build the branch absolute instruction to the escape island.
    255 	long	branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
    256 	if( !err ) {
    257 		long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
    258 		branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
    259 	}
    260 #elif defined(__i386__) || defined(__x86_64__)
    261         if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    262 
    263 	if( !err )
    264 		err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
    265 
    266 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    267 	// Build the jump relative instruction to the escape island
    268 #endif
    269 
    270 
    271 #if defined(__i386__) || defined(__x86_64__)
    272 	if (!err) {
    273 		uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
    274 		addressOffset = OSSwapInt32(addressOffset);
    275 
    276 		jumpRelativeInstruction |= 0xE900000000000000LL;
    277 		jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
    278 		jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
    279 	}
    280 #endif
    281 
    282 	//	Optionally allocate & return the reentry island. This may contain relocated
    283 	//  jmp instructions and so has all the same addressing reachability requirements
    284 	//  the escape island has to the original function, except the escape island is
    285 	//  technically our original function.
    286 	BranchIsland	*reentryIsland = NULL;
    287 	if( !err && originalFunctionReentryIsland ) {
    288 		err = allocateBranchIsland( &reentryIsland, kAllocateHigh, escapeIsland);
    289 		if( !err )
    290 			*originalFunctionReentryIsland = reentryIsland;
    291 	}
    292 
    293 #if defined(__ppc__) || defined(__POWERPC__)
    294 	//	Atomically:
    295 	//	o If the reentry island was allocated:
    296 	//		o Insert the original instruction into the reentry island.
    297 	//		o Target the reentry island at the 2nd instruction of the
    298 	//		  original function.
    299 	//	o Replace the original instruction with the branch absolute.
    300 	if( !err ) {
    301 		int escapeIslandEngaged = false;
    302 		do {
    303 			if( reentryIsland )
    304 				err = setBranchIslandTarget( reentryIsland,
    305 						(void*) (originalFunctionPtr+1), originalInstruction );
    306 			if( !err ) {
    307 				escapeIslandEngaged = CompareAndSwap( originalInstruction,
    308 										branchAbsoluteInstruction,
    309 										(UInt32*)originalFunctionPtr );
    310 				if( !escapeIslandEngaged ) {
    311 					//	Someone replaced the instruction out from under us,
    312 					//	re-read the instruction, make sure it's still not
    313 					//	'mfctr' and try again.
    314 					originalInstruction = *originalFunctionPtr;
    315 					if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
    316 						err = err_cannot_override;
    317 				}
    318 			}
    319 		} while( !err && !escapeIslandEngaged );
    320 	}
    321 #elif defined(__i386__) || defined(__x86_64__)
    322 	// Atomically:
    323 	//	o If the reentry island was allocated:
    324 	//		o Insert the original instructions into the reentry island.
    325 	//		o Target the reentry island at the first non-replaced
    326 	//        instruction of the original function.
    327 	//	o Replace the original first instructions with the jump relative.
    328 	//
    329 	// Note that on i386, we do not support someone else changing the code under our feet
    330 	if ( !err ) {
    331 		fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
    332 					originalInstructionCount, originalInstructionSizes );
    333 
    334 		if( reentryIsland )
    335 			err = setBranchIslandTarget_i386( reentryIsland,
    336 										 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
    337 		// try making islands executable before planting the jmp
    338 #if defined(__x86_64__) || defined(__i386__)
    339         if( !err )
    340             err = makeIslandExecutable(escapeIsland);
    341         if( !err && reentryIsland )
    342             err = makeIslandExecutable(reentryIsland);
    343 #endif
    344 		if ( !err )
    345 			atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
    346 
    347 		mach_error_t prot_err = err_none;
    348 		prot_err = vm_protect( mach_task_self(),
    349 				       (vm_address_t) originalFunctionPtr, 8, false,
    350 				       (VM_PROT_READ | VM_PROT_EXECUTE) );
    351 		if (prot_err) fprintf(stderr, "err = %x %s:%d\n", prot_err, __FILE__, __LINE__);
    352 	}
    353 #endif
    354 
    355 	//	Clean up on error.
    356 	if( err ) {
    357 		if( reentryIsland )
    358 			freeBranchIsland( reentryIsland );
    359 		if( escapeIsland )
    360 			freeBranchIsland( escapeIsland );
    361 	}
    362 
    363 	return err;
    364 }
    365 
    366 /*******************************************************************************
    367 *
    368 *	Implementation
    369 *
    370 *******************************************************************************/
    371 #pragma mark	-
    372 #pragma mark	(Implementation)
    373 
    374 /*******************************************************************************
    375 	Implementation: Allocates memory for a branch island.
    376 
    377 	@param	island			<-	The allocated island.
    378 	@param	allocateHigh	->	Whether to allocate the island at the end of the
    379 								address space (for use with the branch absolute
    380 								instruction).
    381 	@result					<-	mach_error_t
    382 
    383 	***************************************************************************/
    384 
    385 	mach_error_t
    386 allocateBranchIsland(
    387 		BranchIsland	**island,
    388 		int				allocateHigh,
    389 		void *originalFunctionAddress)
    390 {
    391 	assert( island );
    392 
    393 	mach_error_t	err = err_none;
    394 
    395 	if( allocateHigh ) {
    396 		vm_size_t pageSize;
    397 		err = host_page_size( mach_host_self(), &pageSize );
    398 		if( !err ) {
    399 			assert( sizeof( BranchIsland ) <= pageSize );
    400 #if defined(__i386__)
    401 			vm_address_t page = 0;
    402 			mach_error_t err = vm_allocate( mach_task_self(), &page, pageSize, VM_FLAGS_ANYWHERE );
    403 			if( err == err_none ) {
    404 				*island = (BranchIsland*) page;
    405 				return err_none;
    406 			}
    407 			return err;
    408 #else
    409 
    410 #if defined(__ppc__) || defined(__POWERPC__)
    411 			vm_address_t first = 0xfeffffff;
    412 			vm_address_t last = 0xfe000000 + pageSize;
    413 #elif defined(__x86_64__)
    414 			vm_address_t first = ((uint64_t)originalFunctionAddress & ~(uint64_t)(((uint64_t)1 << 31) - 1)) | ((uint64_t)1 << 31); // start in the middle of the page?
    415 			vm_address_t last = 0x0;
    416 #endif
    417 
    418 			vm_address_t page = first;
    419 			int allocated = 0;
    420 			vm_map_t task_self = mach_task_self();
    421 
    422 			while( !err && !allocated && page != last ) {
    423 
    424 				err = vm_allocate( task_self, &page, pageSize, 0 );
    425 				if( err == err_none )
    426 					allocated = 1;
    427 				else if( err == KERN_NO_SPACE ) {
    428 #if defined(__x86_64__)
    429 					page -= pageSize;
    430 #else
    431 					page += pageSize;
    432 #endif
    433 					err = err_none;
    434 				}
    435 			}
    436 			if( allocated )
    437 				*island = (BranchIsland*) page;
    438 			else if( !allocated && !err )
    439 				err = KERN_NO_SPACE;
    440 #endif
    441 		}
    442 	} else {
    443 		void *block = malloc( sizeof( BranchIsland ) );
    444 		if( block )
    445 			*island = block;
    446 		else
    447 			err = KERN_NO_SPACE;
    448 	}
    449 	if( !err )
    450 		(**island).allocatedHigh = allocateHigh;
    451 
    452 	return err;
    453 }
    454 
    455 /*******************************************************************************
    456 	Implementation: Deallocates memory for a branch island.
    457 
    458 	@param	island	->	The island to deallocate.
    459 	@result			<-	mach_error_t
    460 
    461 	***************************************************************************/
    462 
    463 	mach_error_t
    464 freeBranchIsland(
    465 		BranchIsland	*island )
    466 {
    467 	assert( island );
    468 	assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
    469 	assert( island->allocatedHigh );
    470 
    471 	mach_error_t	err = err_none;
    472 
    473 	if( island->allocatedHigh ) {
    474 		vm_size_t pageSize;
    475 		err = host_page_size( mach_host_self(), &pageSize );
    476 		if( !err ) {
    477 			assert( sizeof( BranchIsland ) <= pageSize );
    478 			err = vm_deallocate(
    479 					mach_task_self(),
    480 					(vm_address_t) island, pageSize );
    481 		}
    482 	} else {
    483 		free( island );
    484 	}
    485 
    486 	return err;
    487 }
    488 
    489 /*******************************************************************************
    490 	Implementation: Sets the branch island's target, with an optional
    491 	instruction.
    492 
    493 	@param	island		->	The branch island to insert target into.
    494 	@param	branchTo	->	The address of the target.
    495 	@param	instruction	->	Optional instruction to execute prior to branch. Set
    496 							to zero for nop.
    497 	@result				<-	mach_error_t
    498 
    499 	***************************************************************************/
    500 #if defined(__ppc__) || defined(__POWERPC__)
    501 	mach_error_t
    502 setBranchIslandTarget(
    503 		BranchIsland	*island,
    504 		const void		*branchTo,
    505 		long			instruction )
    506 {
    507 	//	Copy over the template code.
    508     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
    509 
    510     //	Fill in the address.
    511     ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
    512     ((short*)island->instructions)[kAddressHi]
    513     	= (((long) branchTo) >> 16) & 0x0000FFFF;
    514 
    515     //	Fill in the (optional) instuction.
    516     if( instruction != 0 ) {
    517         ((short*)island->instructions)[kInstructionLo]
    518         	= instruction & 0x0000FFFF;
    519         ((short*)island->instructions)[kInstructionHi]
    520         	= (instruction >> 16) & 0x0000FFFF;
    521     }
    522 
    523     //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
    524 	msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
    525 
    526     return err_none;
    527 }
    528 #endif
    529 
    530 #if defined(__i386__)
    531 	mach_error_t
    532 setBranchIslandTarget_i386(
    533 	BranchIsland	*island,
    534 	const void		*branchTo,
    535 	char*			instructions )
    536 {
    537 
    538 	//	Copy over the template code.
    539     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
    540 
    541 	// copy original instructions
    542 	if (instructions) {
    543 		bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
    544 	}
    545 
    546     // Fill in the address.
    547     int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
    548     *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
    549 
    550     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
    551     return err_none;
    552 }
    553 
    554 #elif defined(__x86_64__)
    555 mach_error_t
    556 setBranchIslandTarget_i386(
    557         BranchIsland	*island,
    558         const void		*branchTo,
    559         char*			instructions )
    560 {
    561     // Copy over the template code.
    562     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
    563 
    564     // Copy original instructions.
    565     if (instructions) {
    566         bcopy (instructions, island->instructions, kOriginalInstructionsSize);
    567     }
    568 
    569     //	Fill in the address.
    570     *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
    571     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
    572 
    573     return err_none;
    574 }
    575 #endif
    576 
    577 
    578 #if defined(__i386__) || defined(__x86_64__)
    579 	static Boolean
    580 eatKnownInstructions(
    581 	unsigned char	*code,
    582 	uint64_t		*newInstruction,
    583 	int				*howManyEaten,
    584 	char			*originalInstructions,
    585 	int				*originalInstructionCount,
    586 	uint8_t			*originalInstructionSizes )
    587 {
    588 	Boolean allInstructionsKnown = true;
    589 	int totalEaten = 0;
    590 	int remainsToEat = 5; // a JMP instruction takes 5 bytes
    591 	int instructionIndex = 0;
    592 	ud_t ud_obj;
    593 
    594 	if (howManyEaten) *howManyEaten = 0;
    595 	if (originalInstructionCount) *originalInstructionCount = 0;
    596 	ud_init(&ud_obj);
    597 #if defined(__i386__)
    598 	ud_set_mode(&ud_obj, 32);
    599 #else
    600 	ud_set_mode(&ud_obj, 64);
    601 #endif
    602 	ud_set_input_buffer(&ud_obj, code, 64); // Assume that 'code' points to at least 64bytes of data.
    603 	while (remainsToEat > 0) {
    604 		if (!ud_disassemble(&ud_obj)) {
    605 		    allInstructionsKnown = false;
    606 		    fprintf(stderr, "mach_override: some instructions unknown! Need to update libudis86\n");
    607 		    break;
    608 		}
    609 
    610 		// At this point, we've matched curInstr
    611 		int eaten = ud_insn_len(&ud_obj);
    612 		remainsToEat -= eaten;
    613 		totalEaten += eaten;
    614 
    615 		if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
    616 		instructionIndex += 1;
    617 		if (originalInstructionCount) *originalInstructionCount = instructionIndex;
    618 	}
    619 
    620 
    621 	if (howManyEaten) *howManyEaten = totalEaten;
    622 
    623 	if (originalInstructions) {
    624 		Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
    625 
    626 		if (enoughSpaceForOriginalInstructions) {
    627 			memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
    628 			bcopy(code, originalInstructions, totalEaten);
    629 		} else {
    630 			// printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
    631 			return false;
    632 		}
    633 	}
    634 
    635 	if (allInstructionsKnown) {
    636 		// save last 3 bytes of first 64bits of codre we'll replace
    637 		uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
    638 		currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
    639 		currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
    640 
    641 		// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
    642 		*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
    643 		*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
    644 	}
    645 
    646 	return allInstructionsKnown;
    647 }
    648 
    649 	static void
    650 fixupInstructions(
    651     void		*originalFunction,
    652     void		*escapeIsland,
    653     void		*instructionsToFix,
    654 	int			instructionCount,
    655 	uint8_t		*instructionSizes )
    656 {
    657 	int	index;
    658 	for (index = 0;index < instructionCount;index += 1)
    659 	{
    660 		if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
    661 		{
    662 			uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
    663 			uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
    664 			*jumpOffsetPtr += offset;
    665 		}
    666 
    667 		originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
    668 		escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
    669 		instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
    670     }
    671 }
    672 
    673 #if defined(__i386__)
    674 __asm(
    675 			".text;"
    676 			".align 2, 0x90;"
    677 			"_atomic_mov64:;"
    678 			"	pushl %ebp;"
    679 			"	movl %esp, %ebp;"
    680 			"	pushl %esi;"
    681 			"	pushl %ebx;"
    682 			"	pushl %ecx;"
    683 			"	pushl %eax;"
    684 			"	pushl %edx;"
    685 
    686 			// atomic push of value to an address
    687 			// we use cmpxchg8b, which compares content of an address with
    688 			// edx:eax. If they are equal, it atomically puts 64bit value
    689 			// ecx:ebx in address.
    690 			// We thus put contents of address in edx:eax to force ecx:ebx
    691 			// in address
    692 			"	mov		8(%ebp), %esi;"  // esi contains target address
    693 			"	mov		12(%ebp), %ebx;"
    694 			"	mov		16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
    695 			"	mov		(%esi), %eax;"
    696 			"	mov		4(%esi), %edx;"  // edx:eax now contains value currently contained in target address
    697 			"	lock; cmpxchg8b	(%esi);" // atomic move.
    698 
    699 			// restore registers
    700 			"	popl %edx;"
    701 			"	popl %eax;"
    702 			"	popl %ecx;"
    703 			"	popl %ebx;"
    704 			"	popl %esi;"
    705 			"	popl %ebp;"
    706 			"	ret"
    707 );
    708 #elif defined(__x86_64__)
    709 void atomic_mov64(
    710 		uint64_t *targetAddress,
    711 		uint64_t value )
    712 {
    713     *targetAddress = value;
    714 }
    715 #endif
    716 #endif
    717