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