| OLD | NEW |
| 1 /******************************************************************************* | 1 /******************************************************************************* |
| 2 mach_override.c | 2 mach_override.c |
| 3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzs
ch.com> | 3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzs
ch.com> |
| 4 Some rights reserved: <http://opensource.org/licenses/mit-licens
e.php> | 4 Some rights reserved: <http://opensource.org/licenses/mit-licens
e.php> |
| 5 | 5 |
| 6 ************************************************************************
***/ | 6 ************************************************************************
***/ |
| 7 | 7 |
| 8 #include "mach_override.h" | 8 #include "mach_override.h" |
| 9 | 9 |
| 10 #include <mach-o/dyld.h> | 10 #include <mach-o/dyld.h> |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 | 163 |
| 164 mach_error_t | 164 mach_error_t |
| 165 mach_override_ptr( | 165 mach_override_ptr( |
| 166 void *originalFunctionAddress, | 166 void *originalFunctionAddress, |
| 167 const void *overrideFunctionAddress, | 167 const void *overrideFunctionAddress, |
| 168 void **originalFunctionReentryIsland ) | 168 void **originalFunctionReentryIsland ) |
| 169 { | 169 { |
| 170 assert( originalFunctionAddress ); | 170 assert( originalFunctionAddress ); |
| 171 assert( overrideFunctionAddress ); | 171 assert( overrideFunctionAddress ); |
| 172 | 172 |
| 173 // this addresses overriding such functions as AudioOutputUnitStart() |
| 174 // test with modified DefaultOutputUnit project |
| 175 #if defined(__x86_64__) || defined(__i386__) |
| 176 for(;;){ |
| 177 if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+0x?????
??? |
| 178 originalFunctionAddress=(void*)((char*)originalFunctionAddress+5+*(i
nt32_t *)((char*)originalFunctionAddress+1)); |
| 179 #if defined(__x86_64__) |
| 180 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword nea
r [rip+0x????????] |
| 181 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*
(int32_t *)((uint16_t*)originalFunctionAddress+1)); |
| 182 #elif defined(__i386__) |
| 183 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x??????
?? |
| 184 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddre
ss+1); |
| 185 #endif |
| 186 else break; |
| 187 } |
| 188 #endif |
| 189 |
| 173 long *originalFunctionPtr = (long*) originalFunctionAddress; | 190 long *originalFunctionPtr = (long*) originalFunctionAddress; |
| 174 mach_error_t err = err_none; | 191 mach_error_t err = err_none; |
| 175 | 192 |
| 176 #if defined(__ppc__) || defined(__POWERPC__) | 193 #if defined(__ppc__) || defined(__POWERPC__) |
| 177 // Ensure first instruction isn't 'mfctr'. | 194 // Ensure first instruction isn't 'mfctr'. |
| 178 #define kMFCTRMask 0xfc1fffff | 195 #define kMFCTRMask 0xfc1fffff |
| 179 #define kMFCTRInstruction 0x7c0903a6 | 196 #define kMFCTRInstruction 0x7c0903a6 |
| 180 | 197 |
| 181 long originalInstruction = *originalFunctionPtr; | 198 long originalInstruction = *originalFunctionPtr; |
| 182 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) | 199 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) |
| 183 err = err_cannot_override; | 200 err = err_cannot_override; |
| 184 #elif defined(__i386__) || defined(__x86_64__) | 201 #elif defined(__i386__) || defined(__x86_64__) |
| 185 int eatenCount = 0; | 202 int eatenCount = 0; |
| 186 char originalInstructions[kOriginalInstructionsSize]; | 203 char originalInstructions[kOriginalInstructionsSize]; |
| 187 uint64_t jumpRelativeInstruction = 0; // JMP | 204 uint64_t jumpRelativeInstruction = 0; // JMP |
| 188 | 205 |
| 189 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, | 206 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, |
| 190
&jumpRelativeInstruction, &eatenCount, originalInstructions); | 207
&jumpRelativeInstruction, &eatenCount, originalInstructions); |
| 191 if (eatenCount > kOriginalInstructionsSize) { | 208 if (eatenCount > kOriginalInstructionsSize) { |
| 192 //printf ("Too many instructions eaten\n"); | 209 //printf ("Too many instructions eaten\n"); |
| 193 overridePossible = false; | 210 overridePossible = false; |
| 194 } | 211 } |
| 195 if (!overridePossible) err = err_cannot_override; | 212 if (!overridePossible) err = err_cannot_override; |
| 196 » if (err) printf("err = %x %d\n", err, __LINE__); | 213 » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
| 197 #endif | 214 #endif |
| 198 | 215 |
| 199 // Make the original function implementation writable. | 216 // Make the original function implementation writable. |
| 200 if( !err ) { | 217 if( !err ) { |
| 201 err = vm_protect( mach_task_self(), | 218 err = vm_protect( mach_task_self(), |
| 202 » » » » (vm_address_t) originalFunctionPtr, | 219 » » » » (vm_address_t) originalFunctionPtr, 8, false, |
| 203 » » » » sizeof(long), false, (VM_PROT_ALL | VM_PROT_COPY
) ); | 220 » » » » (VM_PROT_ALL | VM_PROT_COPY) ); |
| 204 if( err ) | 221 if( err ) |
| 205 err = vm_protect( mach_task_self(), | 222 err = vm_protect( mach_task_self(), |
| 206 » » » » » (vm_address_t) originalFunctionPtr, size
of(long), false, | 223 » » » » » (vm_address_t) originalFunctionPtr, 8, f
alse, |
| 207 (VM_PROT_DEFAULT | VM_PROT_COPY) ); | 224 (VM_PROT_DEFAULT | VM_PROT_COPY) ); |
| 208 } | 225 } |
| 209 » if (err) printf("err = %x %d\n", err, __LINE__); | 226 » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
| 210 | 227 |
| 211 // Allocate and target the escape island to the overriding function
. | 228 // Allocate and target the escape island to the overriding function
. |
| 212 BranchIsland *escapeIsland = NULL; | 229 BranchIsland *escapeIsland = NULL; |
| 213 if( !err ) | 230 if( !err ) |
| 214 err = allocateBranchIsland( &escapeIsland, kAllocateHigh, origin
alFunctionAddress ); | 231 err = allocateBranchIsland( &escapeIsland, kAllocateHigh, origin
alFunctionAddress ); |
| 215 » » if (err) printf("err = %x %d\n", err, __LINE__); | 232 » » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LI
NE__); |
| 216 | 233 |
| 217 | 234 |
| 218 #if defined(__ppc__) || defined(__POWERPC__) | 235 #if defined(__ppc__) || defined(__POWERPC__) |
| 219 if( !err ) | 236 if( !err ) |
| 220 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); | 237 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); |
| 221 | 238 |
| 222 // Build the branch absolute instruction to the escape island. | 239 // Build the branch absolute instruction to the escape island. |
| 223 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. | 240 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. |
| 224 if( !err ) { | 241 if( !err ) { |
| 225 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; | 242 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; |
| 226 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; | 243 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; |
| 227 } | 244 } |
| 228 #elif defined(__i386__) || defined(__x86_64__) | 245 #elif defined(__i386__) || defined(__x86_64__) |
| 229 if (err) printf("err = %x %d\n", err, __LINE__); | 246 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
| 230 | 247 |
| 231 if( !err ) | 248 if( !err ) |
| 232 err = setBranchIslandTarget_i386( escapeIsland, overrideFunction
Address, 0 ); | 249 err = setBranchIslandTarget_i386( escapeIsland, overrideFunction
Address, 0 ); |
| 233 | 250 |
| 234 » if (err) printf("err = %x %d\n", err, __LINE__); | 251 » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
| 235 // Build the jump relative instruction to the escape island | 252 // Build the jump relative instruction to the escape island |
| 236 #endif | 253 #endif |
| 237 | 254 |
| 238 | 255 |
| 239 #if defined(__i386__) || defined(__x86_64__) | 256 #if defined(__i386__) || defined(__x86_64__) |
| 240 if (!err) { | 257 if (!err) { |
| 241 » » uint32_t addressOffset = ((void*)escapeIsland - (void*)originalF
unctionPtr - 5); | 258 » » uint32_t addressOffset = ((char*)escapeIsland - (char*)originalF
unctionPtr - 5); |
| 242 addressOffset = OSSwapInt32(addressOffset); | 259 addressOffset = OSSwapInt32(addressOffset); |
| 243 | 260 |
| 244 jumpRelativeInstruction |= 0xE900000000000000LL; | 261 jumpRelativeInstruction |= 0xE900000000000000LL; |
| 245 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; | 262 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; |
| 246 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
| 263 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
|
| 247 } | 264 } |
| 248 #endif | 265 #endif |
| 249 | 266 |
| 250 // Optionally allocate & return the reentry island. | 267 // Optionally allocate & return the reentry island. |
| 251 BranchIsland *reentryIsland = NULL; | 268 BranchIsland *reentryIsland = NULL; |
| 252 if( !err && originalFunctionReentryIsland ) { | 269 if( !err && originalFunctionReentryIsland ) { |
| 253 » » err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NUL
L); | 270 » » err = allocateBranchIsland( &reentryIsland, kAllocateHigh, NULL)
; |
| 254 if( !err ) | 271 if( !err ) |
| 255 *originalFunctionReentryIsland = reentryIsland; | 272 *originalFunctionReentryIsland = reentryIsland; |
| 256 } | 273 } |
| 257 | 274 |
| 258 #if defined(__ppc__) || defined(__POWERPC__) | 275 #if defined(__ppc__) || defined(__POWERPC__) |
| 259 // Atomically: | 276 // Atomically: |
| 260 // o If the reentry island was allocated: | 277 // o If the reentry island was allocated: |
| 261 // o Insert the original instruction into the reentry islan
d. | 278 // o Insert the original instruction into the reentry islan
d. |
| 262 // o Target the reentry island at the 2nd instruction of th
e | 279 // o Target the reentry island at the 2nd instruction of th
e |
| 263 // original function. | 280 // original function. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 289 // o Insert the original instructions into the reentry isla
nd. | 306 // o Insert the original instructions into the reentry isla
nd. |
| 290 // o Target the reentry island at the first non-replaced | 307 // o Target the reentry island at the first non-replaced |
| 291 // instruction of the original function. | 308 // instruction of the original function. |
| 292 // o Replace the original first instructions with the jump relative
. | 309 // o Replace the original first instructions with the jump relative
. |
| 293 // | 310 // |
| 294 // Note that on i386, we do not support someone else changing the code u
nder our feet | 311 // Note that on i386, we do not support someone else changing the code u
nder our feet |
| 295 if ( !err ) { | 312 if ( !err ) { |
| 296 if( reentryIsland ) | 313 if( reentryIsland ) |
| 297 err = setBranchIslandTarget_i386( reentryIsland, | 314 err = setBranchIslandTarget_i386( reentryIsland, |
| 298
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); | 315
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); |
| 316 // try making islands executable before planting the jmp |
| 317 #if defined(__x86_64__) || defined(__i386__) |
| 318 if( !err ) |
| 319 err = makeIslandExecutable(escapeIsland); |
| 320 if( !err && reentryIsland ) |
| 321 err = makeIslandExecutable(reentryIsland); |
| 322 #endif |
| 299 if ( !err ) | 323 if ( !err ) |
| 300 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelati
veInstruction); | 324 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelati
veInstruction); |
| 301 } | 325 } |
| 302 #endif | 326 #endif |
| 303 | 327 |
| 304 #if defined(__i386__) || defined(__x86_64__) | |
| 305 if ( !err ) | |
| 306 err = makeIslandExecutable( escapeIsland ); | |
| 307 if ( !err && reentryIsland ) | |
| 308 err = makeIslandExecutable( reentryIsland ); | |
| 309 #endif | |
| 310 | |
| 311 // Clean up on error. | 328 // Clean up on error. |
| 312 if( err ) { | 329 if( err ) { |
| 313 if( reentryIsland ) | 330 if( reentryIsland ) |
| 314 freeBranchIsland( reentryIsland ); | 331 freeBranchIsland( reentryIsland ); |
| 315 if( escapeIsland ) | 332 if( escapeIsland ) |
| 316 freeBranchIsland( escapeIsland ); | 333 freeBranchIsland( escapeIsland ); |
| 317 } | 334 } |
| 318 | 335 |
| 319 return err; | 336 return err; |
| 320 } | 337 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 else if( err == KERN_NO_SPACE ) { | 390 else if( err == KERN_NO_SPACE ) { |
| 374 #if defined(__x86_64__) | 391 #if defined(__x86_64__) |
| 375 page -= pageSize; | 392 page -= pageSize; |
| 376 #else | 393 #else |
| 377 page += pageSize; | 394 page += pageSize; |
| 378 #endif | 395 #endif |
| 379 err = err_none; | 396 err = err_none; |
| 380 } | 397 } |
| 381 } | 398 } |
| 382 if( allocated ) | 399 if( allocated ) |
| 383 » » » » *island = (void*) page; | 400 » » » » *island = (BranchIsland*) page; |
| 384 else if( !allocated && !err ) | 401 else if( !allocated && !err ) |
| 385 err = KERN_NO_SPACE; | 402 err = KERN_NO_SPACE; |
| 386 } | 403 } |
| 387 } else { | 404 } else { |
| 388 void *block = malloc( sizeof( BranchIsland ) ); | 405 void *block = malloc( sizeof( BranchIsland ) ); |
| 389 if( block ) | 406 if( block ) |
| 390 *island = block; | 407 *island = block; |
| 391 else | 408 else |
| 392 err = KERN_NO_SPACE; | 409 err = KERN_NO_SPACE; |
| 393 } | 410 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 #if defined(__i386__) || defined(__x86_64__) | 540 #if defined(__i386__) || defined(__x86_64__) |
| 524 // simplistic instruction matching | 541 // simplistic instruction matching |
| 525 typedef struct { | 542 typedef struct { |
| 526 unsigned int length; // max 15 | 543 unsigned int length; // max 15 |
| 527 unsigned char mask[15]; // sequence of bytes in memory order | 544 unsigned char mask[15]; // sequence of bytes in memory order |
| 528 unsigned char constraint[15]; // sequence of bytes in memory order | 545 unsigned char constraint[15]; // sequence of bytes in memory order |
| 529 } AsmInstructionMatch; | 546 } AsmInstructionMatch; |
| 530 | 547 |
| 531 #if defined(__i386__) | 548 #if defined(__i386__) |
| 532 static AsmInstructionMatch possibleInstructions[] = { | 549 static AsmInstructionMatch possibleInstructions[] = { |
| 550 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },
// push %ebp; mov %esp,%ebp; leave; ret |
| 533 { 0x1, {0xFF}, {0x90} },
// nop | 551 { 0x1, {0xFF}, {0x90} },
// nop |
| 534 { 0x1, {0xFF}, {0x55} },
// push %esp | 552 { 0x1, {0xFF}, {0x55} },
// push %esp |
| 535 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp | 553 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp |
| 536 { 0x1, {0xFF}, {0x53} },
// push %ebx | 554 { 0x1, {0xFF}, {0x53} },
// push %ebx |
| 537 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp | 555 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp |
| 538 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate | 556 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate |
| 539 { 0x1, {0xFF}, {0x57} },
// push %edi | 557 { 0x1, {0xFF}, {0x57} },
// push %edi |
| 540 { 0x1, {0xFF}, {0x56} },
// push %esi | 558 { 0x1, {0xFF}, {0x56} },
// push %esi |
| 541 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax | 559 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax |
| 560 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %re
g |
| 561 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx)
, %reg |
| 562 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $im
m(%esp), %ecx |
| 542 { 0x0 } | 563 { 0x0 } |
| 543 }; | 564 }; |
| 544 #elif defined(__x86_64__) | 565 #elif defined(__x86_64__) |
| 545 static AsmInstructionMatch possibleInstructions[] = { | 566 static AsmInstructionMatch possibleInstructions[] = { |
| 546 { 0x1, {0xFF}, {0x90} },
// nop | 567 { 0x1, {0xFF}, {0x90} },
// nop |
| 547 { 0x1, {0xF8}, {0x50} },
// push %rX | 568 { 0x1, {0xF8}, {0x50} },
// push %rX |
| 548 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp | 569 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp |
| 549 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp | 570 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp |
| 550 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp | 571 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp |
| 551 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX | 572 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX |
| 552 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX | 573 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX |
| 574 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %reg |
| 575 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi) |
| 553 { 0x0 } | 576 { 0x0 } |
| 554 }; | 577 }; |
| 555 #endif | 578 #endif |
| 556 | 579 |
| 557 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) | 580 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) |
| 558 { | 581 { |
| 559 Boolean match = true; | 582 Boolean match = true; |
| 560 | 583 |
| 561 size_t i; | 584 size_t i; |
| 562 for (i=0; i<instruction->length; i++) { | 585 for (i=0; i<instruction->length; i++) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 591 // See if instruction matches one we know | 614 // See if instruction matches one we know |
| 592 AsmInstructionMatch* curInstr = possibleInstructions; | 615 AsmInstructionMatch* curInstr = possibleInstructions; |
| 593 do { | 616 do { |
| 594 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; | 617 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; |
| 595 curInstr++; | 618 curInstr++; |
| 596 } while (curInstr->length > 0); | 619 } while (curInstr->length > 0); |
| 597 | 620 |
| 598 // if all instruction matches failed, we don't know current inst
ruction then, stop here | 621 // if all instruction matches failed, we don't know current inst
ruction then, stop here |
| 599 if (!curInstructionKnown) { | 622 if (!curInstructionKnown) { |
| 600 allInstructionsKnown = false; | 623 allInstructionsKnown = false; |
| 624 fprintf(stderr, "mach_override: some instructions unknow
n! Need to update mach_override.c\n"); |
| 601 break; | 625 break; |
| 602 } | 626 } |
| 603 | 627 |
| 604 // At this point, we've matched curInstr | 628 // At this point, we've matched curInstr |
| 605 int eaten = curInstr->length; | 629 int eaten = curInstr->length; |
| 606 ptr += eaten; | 630 ptr += eaten; |
| 607 remainsToEat -= eaten; | 631 remainsToEat -= eaten; |
| 608 totalEaten += eaten; | 632 totalEaten += eaten; |
| 609 } | 633 } |
| 610 | 634 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 ); | 699 ); |
| 676 #elif defined(__x86_64__) | 700 #elif defined(__x86_64__) |
| 677 void atomic_mov64( | 701 void atomic_mov64( |
| 678 uint64_t *targetAddress, | 702 uint64_t *targetAddress, |
| 679 uint64_t value ) | 703 uint64_t value ) |
| 680 { | 704 { |
| 681 *targetAddress = value; | 705 *targetAddress = value; |
| 682 } | 706 } |
| 683 #endif | 707 #endif |
| 684 #endif | 708 #endif |
| OLD | NEW |