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
30long 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
49char 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
66char 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
92typedef	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
106allocateBranchIsland(
107		BranchIsland	**island,
108		int				allocateHigh,
109		void *originalFunctionAddress);
110
111	mach_error_t
112freeBranchIsland(
113		BranchIsland	*island );
114
115#if defined(__ppc__) || defined(__POWERPC__)
116	mach_error_t
117setBranchIslandTarget(
118		BranchIsland	*island,
119		const void		*branchTo,
120		long			instruction );
121#endif
122
123#if defined(__i386__) || defined(__x86_64__)
124mach_error_t
125setBranchIslandTarget_i386(
126						   BranchIsland	*island,
127						   const void		*branchTo,
128						   char*			instructions );
129void
130atomic_mov64(
131		uint64_t *targetAddress,
132		uint64_t value );
133
134	static Boolean
135eatKnownInstructions(
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
144fixupInstructions(
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__)
161mach_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
177mach_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
386allocateBranchIsland(
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
464freeBranchIsland(
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
502setBranchIslandTarget(
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
532setBranchIslandTarget_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__)
555mach_error_t
556setBranchIslandTarget_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
580eatKnownInstructions(
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
650fixupInstructions(
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__)
709void atomic_mov64(
710		uint64_t *targetAddress,
711		uint64_t value )
712{
713    *targetAddress = value;
714}
715#endif
716#endif
717