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
29long 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
48char 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
65char 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
91typedef	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
105allocateBranchIsland(
106		BranchIsland	**island,
107		int				allocateHigh,
108		void *originalFunctionAddress);
109
110	mach_error_t
111freeBranchIsland(
112		BranchIsland	*island );
113
114#if defined(__ppc__) || defined(__POWERPC__)
115	mach_error_t
116setBranchIslandTarget(
117		BranchIsland	*island,
118		const void		*branchTo,
119		long			instruction );
120#endif
121
122#if defined(__i386__) || defined(__x86_64__)
123mach_error_t
124setBranchIslandTarget_i386(
125						   BranchIsland	*island,
126						   const void		*branchTo,
127						   char*			instructions );
128void
129atomic_mov64(
130		uint64_t *targetAddress,
131		uint64_t value );
132
133	static Boolean
134eatKnownInstructions(
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
143fixupInstructions(
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__)
160mach_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
174mach_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
382allocateBranchIsland(
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
454freeBranchIsland(
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
486setBranchIslandTarget(
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
516setBranchIslandTarget_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__)
539mach_error_t
540setBranchIslandTarget_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
564eatKnownInstructions(
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
634fixupInstructions(
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__)
693void atomic_mov64(
694		uint64_t *targetAddress,
695		uint64_t value )
696{
697    *targetAddress = value;
698}
699#endif
700#endif
701