1 /*******************************************************************************
3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
4 Some rights reserved: <http://opensource.org/licenses/mit-license.php>
6 ***************************************************************************/
8 #include "mach_override.h"
10 #include <mach-o/dyld.h>
11 #include <mach/mach_host.h>
12 #include <mach/mach_init.h>
13 #include <mach/vm_map.h>
16 #include <CoreServices/CoreServices.h>
18 /**************************
22 **************************/
24 #pragma mark (Constants)
26 #define kPageSize 4096
27 #if defined(__ppc__) || defined(__POWERPC__)
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
41 #define kInstructionHi 10
42 #define kInstructionLo 11
44 #elif defined(__i386__)
46 #define kOriginalInstructionsSize 16
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
57 #define kInstructions 0
58 #define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
59 #elif defined(__x86_64__)
61 #define kOriginalInstructionsSize 32
63 #define kJumpAddress kOriginalInstructionsSize + 6
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
80 /**************************
84 **************************/
86 #pragma mark (Data Types)
89 char instructions
[sizeof(kIslandTemplate
)];
92 /**************************
96 **************************/
98 #pragma mark (Funky Protos)
101 allocateBranchIsland(
102 BranchIsland
**island
,
103 void *originalFunctionAddress
);
107 BranchIsland
*island
);
109 #if defined(__ppc__) || defined(__POWERPC__)
111 setBranchIslandTarget(
112 BranchIsland
*island
,
113 const void *branchTo
,
117 #if defined(__i386__) || defined(__x86_64__)
119 setBranchIslandTarget_i386(
120 BranchIsland
*island
,
121 const void *branchTo
,
122 char* instructions
);
125 uint64_t *targetAddress
,
129 eatKnownInstructions(
131 uint64_t *newInstruction
,
133 char *originalInstructions
,
134 int *originalInstructionCount
,
135 uint8_t *originalInstructionSizes
);
139 void *originalFunction
,
141 void *instructionsToFix
,
142 int instructionCount
,
143 uint8_t *instructionSizes
);
146 /*******************************************************************************
150 *******************************************************************************/
152 #pragma mark (Interface)
154 #if defined(__i386__) || defined(__x86_64__)
155 mach_error_t
makeIslandExecutable(void *address
) {
156 mach_error_t err
= err_none
;
157 uintptr_t page
= (uintptr_t)address
& ~(uintptr_t)(kPageSize
-1);
159 e
|= mprotect((void *)page
, kPageSize
, PROT_EXEC
| PROT_READ
| PROT_WRITE
);
160 e
|= msync((void *)page
, kPageSize
, MS_INVALIDATE
);
162 err
= err_cannot_override
;
170 void *originalFunctionAddress
,
171 const void *overrideFunctionAddress
,
172 void **originalFunctionReentryIsland
)
174 assert( originalFunctionAddress
);
175 assert( overrideFunctionAddress
);
177 // this addresses overriding such functions as AudioOutputUnitStart()
178 // test with modified DefaultOutputUnit project
179 #if defined(__x86_64__)
181 if(*(uint16_t*)originalFunctionAddress
==0x25FF) // jmp qword near [rip+0x????????]
182 originalFunctionAddress
=*(void**)((char*)originalFunctionAddress
+6+*(int32_t *)((uint16_t*)originalFunctionAddress
+1));
185 #elif defined(__i386__)
187 if(*(uint16_t*)originalFunctionAddress
==0x25FF) // jmp *0x????????
188 originalFunctionAddress
=**(void***)((uint16_t*)originalFunctionAddress
+1);
193 long *originalFunctionPtr
= (long*) originalFunctionAddress
;
194 mach_error_t err
= err_none
;
196 #if defined(__ppc__) || defined(__POWERPC__)
197 // Ensure first instruction isn't 'mfctr'.
198 #define kMFCTRMask 0xfc1fffff
199 #define kMFCTRInstruction 0x7c0903a6
201 long originalInstruction
= *originalFunctionPtr
;
202 if( !err
&& ((originalInstruction
& kMFCTRMask
) == kMFCTRInstruction
) )
203 err
= err_cannot_override
;
204 #elif defined(__i386__) || defined(__x86_64__)
206 int originalInstructionCount
= 0;
207 char originalInstructions
[kOriginalInstructionsSize
];
208 uint8_t originalInstructionSizes
[kOriginalInstructionsSize
];
209 uint64_t jumpRelativeInstruction
= 0; // JMP
211 Boolean overridePossible
= eatKnownInstructions ((unsigned char *)originalFunctionPtr
,
212 &jumpRelativeInstruction
, &eatenCount
,
213 originalInstructions
, &originalInstructionCount
,
214 originalInstructionSizes
);
215 if (eatenCount
> kOriginalInstructionsSize
) {
216 //printf ("Too many instructions eaten\n");
217 overridePossible
= false;
219 if (!overridePossible
) err
= err_cannot_override
;
220 if (err
) fprintf(stderr
, "err = %x %s:%d\n", err
, __FILE__
, __LINE__
);
223 // Make the original function implementation writable.
225 err
= vm_protect( mach_task_self(),
226 (vm_address_t
) originalFunctionPtr
, 8, false,
227 (VM_PROT_ALL
| VM_PROT_COPY
) );
229 err
= vm_protect( mach_task_self(),
230 (vm_address_t
) originalFunctionPtr
, 8, false,
231 (VM_PROT_DEFAULT
| VM_PROT_COPY
) );
233 if (err
) fprintf(stderr
, "err = %x %s:%d\n", err
, __FILE__
, __LINE__
);
235 // Allocate and target the escape island to the overriding function.
236 BranchIsland
*escapeIsland
= NULL
;
238 err
= allocateBranchIsland( &escapeIsland
, originalFunctionAddress
);
239 if (err
) fprintf(stderr
, "err = %x %s:%d\n", err
, __FILE__
, __LINE__
);
242 #if defined(__ppc__) || defined(__POWERPC__)
244 err
= setBranchIslandTarget( escapeIsland
, overrideFunctionAddress
, 0 );
246 // Build the branch absolute instruction to the escape island.
247 long branchAbsoluteInstruction
= 0; // Set to 0 just to silence warning.
249 long escapeIslandAddress
= ((long) escapeIsland
) & 0x3FFFFFF;
250 branchAbsoluteInstruction
= 0x48000002 | escapeIslandAddress
;
252 #elif defined(__i386__) || defined(__x86_64__)
253 if (err
) fprintf(stderr
, "err = %x %s:%d\n", err
, __FILE__
, __LINE__
);
256 err
= setBranchIslandTarget_i386( escapeIsland
, overrideFunctionAddress
, 0 );
258 if (err
) fprintf(stderr
, "err = %x %s:%d\n", err
, __FILE__
, __LINE__
);
259 // Build the jump relative instruction to the escape island
263 #if defined(__i386__) || defined(__x86_64__)
265 uint32_t addressOffset
= ((char*)escapeIsland
- (char*)originalFunctionPtr
- 5);
266 addressOffset
= OSSwapInt32(addressOffset
);
268 jumpRelativeInstruction
|= 0xE900000000000000LL
;
269 jumpRelativeInstruction
|= ((uint64_t)addressOffset
& 0xffffffff) << 24;
270 jumpRelativeInstruction
= OSSwapInt64(jumpRelativeInstruction
);
274 // Optionally allocate & return the reentry island. This may contain relocated
275 // jmp instructions and so has all the same addressing reachability requirements
276 // the escape island has to the original function, except the escape island is
277 // technically our original function.
278 BranchIsland
*reentryIsland
= NULL
;
279 if( !err
&& originalFunctionReentryIsland
) {
280 err
= allocateBranchIsland( &reentryIsland
, escapeIsland
);
282 *originalFunctionReentryIsland
= reentryIsland
;
285 #if defined(__ppc__) || defined(__POWERPC__)
287 // o If the reentry island was allocated:
288 // o Insert the original instruction into the reentry island.
289 // o Target the reentry island at the 2nd instruction of the
290 // original function.
291 // o Replace the original instruction with the branch absolute.
293 int escapeIslandEngaged
= false;
296 err
= setBranchIslandTarget( reentryIsland
,
297 (void*) (originalFunctionPtr
+1), originalInstruction
);
299 escapeIslandEngaged
= CompareAndSwap( originalInstruction
,
300 branchAbsoluteInstruction
,
301 (UInt32
*)originalFunctionPtr
);
302 if( !escapeIslandEngaged
) {
303 // Someone replaced the instruction out from under us,
304 // re-read the instruction, make sure it's still not
305 // 'mfctr' and try again.
306 originalInstruction
= *originalFunctionPtr
;
307 if( (originalInstruction
& kMFCTRMask
) == kMFCTRInstruction
)
308 err
= err_cannot_override
;
311 } while( !err
&& !escapeIslandEngaged
);
313 #elif defined(__i386__) || defined(__x86_64__)
315 // o If the reentry island was allocated:
316 // o Insert the original instructions into the reentry island.
317 // o Target the reentry island at the first non-replaced
318 // instruction of the original function.
319 // o Replace the original first instructions with the jump relative.
321 // Note that on i386, we do not support someone else changing the code under our feet
323 fixupInstructions(originalFunctionPtr
, reentryIsland
, originalInstructions
,
324 originalInstructionCount
, originalInstructionSizes
);
327 err
= setBranchIslandTarget_i386( reentryIsland
,
328 (void*) ((char *)originalFunctionPtr
+eatenCount
), originalInstructions
);
329 // try making islands executable before planting the jmp
330 #if defined(__x86_64__) || defined(__i386__)
332 err
= makeIslandExecutable(escapeIsland
);
333 if( !err
&& reentryIsland
)
334 err
= makeIslandExecutable(reentryIsland
);
337 atomic_mov64((uint64_t *)originalFunctionPtr
, jumpRelativeInstruction
);
341 // Clean up on error.
344 freeBranchIsland( reentryIsland
);
346 freeBranchIsland( escapeIsland
);
352 /*******************************************************************************
356 *******************************************************************************/
358 #pragma mark (Implementation)
360 /***************************************************************************//**
361 Implementation: Allocates memory for a branch island.
363 @param island <- The allocated island.
364 @result <- mach_error_t
366 ***************************************************************************/
369 allocateBranchIsland(
370 BranchIsland
**island
,
371 void *originalFunctionAddress
)
375 assert( sizeof( BranchIsland
) <= kPageSize
);
376 #if defined(__ppc__) || defined(__POWERPC__)
377 vm_address_t first
= 0xfeffffff;
378 vm_address_t last
= 0xfe000000 + kPageSize
;
379 #elif defined(__x86_64__)
380 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?
381 vm_address_t last
= 0x0;
383 vm_address_t first
= 0xffc00000;
384 vm_address_t last
= 0xfffe0000;
387 vm_address_t page
= first
;
388 vm_map_t task_self
= mach_task_self();
390 while( page
!= last
) {
391 mach_error_t err
= vm_allocate( task_self
, &page
, kPageSize
, 0 );
392 if( err
== err_none
) {
393 *island
= (BranchIsland
*) page
;
396 if( err
!= KERN_NO_SPACE
)
398 #if defined(__x86_64__)
406 return KERN_NO_SPACE
;
409 /***************************************************************************//**
410 Implementation: Deallocates memory for a branch island.
412 @param island -> The island to deallocate.
413 @result <- mach_error_t
415 ***************************************************************************/
419 BranchIsland
*island
)
422 assert( (*(long*)&island
->instructions
[0]) == kIslandTemplate
[0] );
423 assert( sizeof( BranchIsland
) <= kPageSize
);
424 return vm_deallocate( mach_task_self(), (vm_address_t
) island
,
428 /***************************************************************************//**
429 Implementation: Sets the branch island's target, with an optional
432 @param island -> The branch island to insert target into.
433 @param branchTo -> The address of the target.
434 @param instruction -> Optional instruction to execute prior to branch. Set
436 @result <- mach_error_t
438 ***************************************************************************/
439 #if defined(__ppc__) || defined(__POWERPC__)
441 setBranchIslandTarget(
442 BranchIsland
*island
,
443 const void *branchTo
,
446 // Copy over the template code.
447 bcopy( kIslandTemplate
, island
->instructions
, sizeof( kIslandTemplate
) );
449 // Fill in the address.
450 ((short*)island
->instructions
)[kAddressLo
] = ((long) branchTo
) & 0x0000FFFF;
451 ((short*)island
->instructions
)[kAddressHi
]
452 = (((long) branchTo
) >> 16) & 0x0000FFFF;
454 // Fill in the (optional) instuction.
455 if( instruction
!= 0 ) {
456 ((short*)island
->instructions
)[kInstructionLo
]
457 = instruction
& 0x0000FFFF;
458 ((short*)island
->instructions
)[kInstructionHi
]
459 = (instruction
>> 16) & 0x0000FFFF;
462 //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
463 msync( island
->instructions
, sizeof( kIslandTemplate
), MS_INVALIDATE
);
469 #if defined(__i386__)
471 setBranchIslandTarget_i386(
472 BranchIsland
*island
,
473 const void *branchTo
,
477 // Copy over the template code.
478 bcopy( kIslandTemplate
, island
->instructions
, sizeof( kIslandTemplate
) );
480 // copy original instructions
482 bcopy (instructions
, island
->instructions
+ kInstructions
, kOriginalInstructionsSize
);
485 // Fill in the address.
486 int32_t addressOffset
= (char *)branchTo
- (island
->instructions
+ kJumpAddress
+ 4);
487 *((int32_t *)(island
->instructions
+ kJumpAddress
)) = addressOffset
;
489 msync( island
->instructions
, sizeof( kIslandTemplate
), MS_INVALIDATE
);
493 #elif defined(__x86_64__)
495 setBranchIslandTarget_i386(
496 BranchIsland
*island
,
497 const void *branchTo
,
500 // Copy over the template code.
501 bcopy( kIslandTemplate
, island
->instructions
, sizeof( kIslandTemplate
) );
503 // Copy original instructions.
505 bcopy (instructions
, island
->instructions
, kOriginalInstructionsSize
);
508 // Fill in the address.
509 *((uint64_t *)(island
->instructions
+ kJumpAddress
)) = (uint64_t)branchTo
;
510 msync( island
->instructions
, sizeof( kIslandTemplate
), MS_INVALIDATE
);
517 #if defined(__i386__) || defined(__x86_64__)
518 // simplistic instruction matching
520 unsigned int length
; // max 15
521 unsigned char mask
[15]; // sequence of bytes in memory order
522 unsigned char constraint
[15]; // sequence of bytes in memory order
523 } AsmInstructionMatch
;
525 #if defined(__i386__)
526 static AsmInstructionMatch possibleInstructions
[] = {
527 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
528 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
529 { 0x1, {0xFF}, {0x90} }, // nop
530 { 0x1, {0xFF}, {0x55} }, // push %esp
531 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
532 { 0x1, {0xFF}, {0x53} }, // push %ebx
533 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
534 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
535 { 0x1, {0xFF}, {0x57} }, // push %edi
536 { 0x1, {0xFF}, {0x56} }, // push %esi
537 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
538 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
539 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
540 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
541 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
544 #elif defined(__x86_64__)
545 static AsmInstructionMatch possibleInstructions
[] = {
546 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
547 { 0x1, {0xFF}, {0x90} }, // nop
548 { 0x1, {0xF8}, {0x50} }, // push %rX
549 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
550 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
551 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
552 { 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
553 { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
554 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
555 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
556 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
557 { 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %eax
562 static Boolean
codeMatchesInstruction(unsigned char *code
, AsmInstructionMatch
* instruction
)
564 Boolean match
= true;
567 for (i
=0; i
<instruction
->length
; i
++) {
568 unsigned char mask
= instruction
->mask
[i
];
569 unsigned char constraint
= instruction
->constraint
[i
];
570 unsigned char codeValue
= code
[i
];
572 match
= ((codeValue
& mask
) == constraint
);
579 #if defined(__i386__) || defined(__x86_64__)
581 eatKnownInstructions(
583 uint64_t *newInstruction
,
585 char *originalInstructions
,
586 int *originalInstructionCount
,
587 uint8_t *originalInstructionSizes
)
589 Boolean allInstructionsKnown
= true;
591 unsigned char* ptr
= code
;
592 int remainsToEat
= 5; // a JMP instruction takes 5 bytes
593 int instructionIndex
= 0;
595 if (howManyEaten
) *howManyEaten
= 0;
596 if (originalInstructionCount
) *originalInstructionCount
= 0;
597 while (remainsToEat
> 0) {
598 Boolean curInstructionKnown
= false;
600 // See if instruction matches one we know
601 AsmInstructionMatch
* curInstr
= possibleInstructions
;
603 if ((curInstructionKnown
= codeMatchesInstruction(ptr
, curInstr
))) break;
605 } while (curInstr
->length
> 0);
607 // if all instruction matches failed, we don't know current instruction then, stop here
608 if (!curInstructionKnown
) {
609 allInstructionsKnown
= false;
610 fprintf(stderr
, "mach_override: some instructions unknown! Need to update mach_override.c\n");
614 // At this point, we've matched curInstr
615 int eaten
= curInstr
->length
;
617 remainsToEat
-= eaten
;
620 if (originalInstructionSizes
) originalInstructionSizes
[instructionIndex
] = eaten
;
621 instructionIndex
+= 1;
622 if (originalInstructionCount
) *originalInstructionCount
= instructionIndex
;
626 if (howManyEaten
) *howManyEaten
= totalEaten
;
628 if (originalInstructions
) {
629 Boolean enoughSpaceForOriginalInstructions
= (totalEaten
< kOriginalInstructionsSize
);
631 if (enoughSpaceForOriginalInstructions
) {
632 memset(originalInstructions
, 0x90 /* NOP */, kOriginalInstructionsSize
); // fill instructions with NOP
633 bcopy(code
, originalInstructions
, totalEaten
);
635 // printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
640 if (allInstructionsKnown
) {
641 // save last 3 bytes of first 64bits of codre we'll replace
642 uint64_t currentFirst64BitsOfCode
= *((uint64_t *)code
);
643 currentFirst64BitsOfCode
= OSSwapInt64(currentFirst64BitsOfCode
); // back to memory representation
644 currentFirst64BitsOfCode
&= 0x0000000000FFFFFFLL
;
646 // keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
647 *newInstruction
&= 0xFFFFFFFFFF000000LL
; // clear last 3 bytes
648 *newInstruction
|= (currentFirst64BitsOfCode
& 0x0000000000FFFFFFLL
); // set last 3 bytes
651 return allInstructionsKnown
;
656 void *originalFunction
,
658 void *instructionsToFix
,
659 int instructionCount
,
660 uint8_t *instructionSizes
)
663 for (index
= 0;index
< instructionCount
;index
+= 1)
665 if (*(uint8_t*)instructionsToFix
== 0xE9) // 32-bit jump relative
667 uint32_t offset
= (uintptr_t)originalFunction
- (uintptr_t)escapeIsland
;
668 uint32_t *jumpOffsetPtr
= (uint32_t*)((uintptr_t)instructionsToFix
+ 1);
669 *jumpOffsetPtr
+= offset
;
672 originalFunction
= (void*)((uintptr_t)originalFunction
+ instructionSizes
[index
]);
673 escapeIsland
= (void*)((uintptr_t)escapeIsland
+ instructionSizes
[index
]);
674 instructionsToFix
= (void*)((uintptr_t)instructionsToFix
+ instructionSizes
[index
]);
679 #if defined(__i386__)
692 // atomic push of value to an address
693 // we use cmpxchg8b, which compares content of an address with
694 // edx:eax. If they are equal, it atomically puts 64bit value
695 // ecx:ebx in address.
696 // We thus put contents of address in edx:eax to force ecx:ebx
698 " mov 8(%ebp), %esi;" // esi contains target address
699 " mov 12(%ebp), %ebx;"
700 " mov 16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
702 " mov 4(%esi), %edx;" // edx:eax now contains value currently contained in target address
703 " lock; cmpxchg8b (%esi);" // atomic move.
714 #elif defined(__x86_64__)
716 uint64_t *targetAddress
,
719 *targetAddress
= value
;