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__) 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 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 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 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 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 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 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 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 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__) 693 void atomic_mov64( 694 uint64_t *targetAddress, 695 uint64_t value ) 696 { 697 *targetAddress = value; 698 } 699 #endif 700 #endif 701