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