1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_ 18#define ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_ 19 20#include "asm_support_x86_64.h" 21#include "interpreter/cfi_asm_support.h" 22 23// Regular gas(1) & current clang/llvm assembler support named macro parameters. 24#define MACRO0(macro_name) .macro macro_name 25#define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1 26#define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2 27#define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3 28#define MACRO4(macro_name, macro_arg1, macro_arg2, macro_arg3, macro_arg4) .macro macro_name macro_arg1, macro_arg2, macro_arg3, macro_arg4 29#define END_MACRO .endm 30 31#if defined(__clang__) 32 // Clang/llvm does not support .altmacro. However, the clang/llvm preprocessor doesn't 33 // separate the backslash and parameter by a space. Everything just works. 34 #define RAW_VAR(name) \name 35 #define VAR(name) \name 36 #define CALLVAR(name) SYMBOL(\name) 37 #define PLT_VAR(name) \name@PLT 38 #define REG_VAR(name) %\name 39 #define CALL_MACRO(name) \name 40#else 41 // Regular gas(1) uses \argument_name for macro arguments. 42 // We need to turn on alternate macro syntax so we can use & instead or the preprocessor 43 // will screw us by inserting a space between the \ and the name. Even in this mode there's 44 // no special meaning to $, so literals are still just $x. The use of altmacro means % is a 45 // special character meaning care needs to be taken when passing registers as macro 46 // arguments. 47 .altmacro 48 #define RAW_VAR(name) name& 49 #define VAR(name) name& 50 #define CALLVAR(name) SYMBOL(name&) 51 #define PLT_VAR(name) name&@PLT 52 #define REG_VAR(name) %name 53 #define CALL_MACRO(name) name& 54#endif 55 56#define LITERAL(value) $value 57#if defined(__APPLE__) 58 #define MACRO_LITERAL(value) $(value) 59#else 60 #define MACRO_LITERAL(value) $value 61#endif 62 63#if defined(__APPLE__) 64 #define FUNCTION_TYPE(name) 65 #define SIZE(name) 66#else 67 #define FUNCTION_TYPE(name) .type name, @function 68 #define SIZE(name) .size name, .-name 69#endif 70 71 // CFI support. 72#if !defined(__APPLE__) 73 #define CFI_STARTPROC .cfi_startproc 74 #define CFI_ENDPROC .cfi_endproc 75 #define CFI_ADJUST_CFA_OFFSET(size) .cfi_adjust_cfa_offset size 76 #define CFI_DEF_CFA(reg,size) .cfi_def_cfa reg,size 77 #define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg 78 #define CFI_RESTORE(reg) .cfi_restore reg 79 #define CFI_REL_OFFSET(reg,size) .cfi_rel_offset reg,size 80 #define CFI_REGISTER(orig_reg, current_reg) .cfi_register orig_reg, current_reg 81 #define CFI_REMEMBER_STATE .cfi_remember_state 82 // The spec is not clear whether the CFA is part of the saved state and tools 83 // differ in the behaviour, so explicitly set the CFA to avoid any ambiguity. 84 // The restored CFA state should match the CFA state during CFI_REMEMBER_STATE. 85 // `objdump -Wf libart.so | egrep "_cfa|_state"` is useful to audit the opcodes. 86 #define CFI_RESTORE_STATE_AND_DEF_CFA(reg,off) .cfi_restore_state .cfi_def_cfa reg,off 87 #define CFI_RESTORE_STATE .cfi_restore_state 88#else 89 // Mac OS' doesn't like cfi_* directives. 90 #define CFI_STARTPROC 91 #define CFI_ENDPROC 92 #define CFI_ADJUST_CFA_OFFSET(size) 93 #define CFI_DEF_CFA(reg,size) 94 #define CFI_DEF_CFA_REGISTER(reg) 95 #define CFI_RESTORE(reg) 96 #define CFI_REL_OFFSET(reg,size) 97 #define CFI_REGISTER(orig_reg, current_reg) 98 #define CFI_REMEMBER_STATE 99 #define CFI_RESTORE_STATE_AND_DEF_CFA(off) 100 #define CFI_RESTORE_STATE 101#endif 102 103// The register numbers are a bit mixed up for x86-64. 104#define CFI_REG_rax 0 105#define CFI_REG_rcx 2 106#define CFI_REG_rdx 1 107#define CFI_REG_rbx 3 108#define CFI_REG_rsp 7 109#define CFI_REG_rbp 6 110#define CFI_REG_rsi 4 111#define CFI_REG_rdi 5 112#define CFI_REG_r8 8 113#define CFI_REG_r9 9 114#define CFI_REG_r10 10 115#define CFI_REG_r11 11 116#define CFI_REG_r12 12 117#define CFI_REG_r13 13 118#define CFI_REG_r14 14 119#define CFI_REG_r15 15 120#define CFI_REG_rip 16 121 122#define CFI_REG(reg) CFI_REG_##reg 123 124MACRO3(CFI_EXPRESSION_BREG, n, b, offset) 125 .if (-0x40 <= (\offset)) && ((\offset) < 0x40) 126 CFI_EXPRESSION_BREG_1(\n, \b, \offset) 127 .elseif (-0x2000 <= (\offset)) && ((\offset) < 0x2000) 128 CFI_EXPRESSION_BREG_2(\n, \b, \offset) 129 .else 130 .error "Unsupported offset" 131 .endif 132END_MACRO 133 134MACRO3(CFI_DEF_CFA_BREG_PLUS_UCONST, reg, offset, size) 135 .if ((\size) < 0) 136 .error "Size should be positive" 137 .endif 138 .if (((\offset) < -0x40) || ((\offset) >= 0x40)) 139 .error "Unsupported offset" 140 .endif 141 .if ((\size) < 0x80) 142 CFI_DEF_CFA_BREG_PLUS_UCONST_1_1(\reg, \offset, \size) 143 .elseif ((\size) < 0x4000) 144 CFI_DEF_CFA_BREG_PLUS_UCONST_1_2(\reg, \offset, \size) 145 .else 146 .error "Unsupported size" 147 .endif 148END_MACRO 149 150 // Symbols. 151#if !defined(__APPLE__) 152 #define SYMBOL(name) name 153 #define PLT_SYMBOL(name) name ## @PLT 154#else 155 #define SYMBOL(name) _ ## name 156 #define PLT_SYMBOL(name) _ ## name 157#endif 158 159// Directive to hide a function symbol. 160#if defined(__APPLE__) 161 #define ASM_HIDDEN .private_extern 162#else 163 #define ASM_HIDDEN .hidden 164#endif 165 166 /* Cache alignment for function entry */ 167MACRO0(ALIGN_FUNCTION_ENTRY) 168 // ART-compiled functions have OatQuickMethodHeader but assembly funtions do not. 169 // Prefix the assembly code with 0xFFs, which means there is no method header. 170 .byte 0xFF, 0xFF, 0xFF, 0xFF 171 // Cache alignment for function entry. 172 .balign 16, 0xFF 173END_MACRO 174 175// TODO: we might need to use SYMBOL() here to add the underscore prefix 176// for mac builds. 177MACRO2(DEFINE_FUNCTION_CUSTOM_CFA, c_name, cfa_offset) 178 FUNCTION_TYPE(SYMBOL(\c_name)) 179 ASM_HIDDEN CALLVAR(c_name) 180 .globl CALLVAR(c_name) 181 ALIGN_FUNCTION_ENTRY 182CALLVAR(c_name): 183 CFI_STARTPROC 184 // Ensure we get an appropriate starting CFA. 185 CFI_DEF_CFA(rsp, RAW_VAR(cfa_offset)) 186END_MACRO 187 188MACRO1(DEFINE_FUNCTION, c_name) 189 DEFINE_FUNCTION_CUSTOM_CFA RAW_VAR(c_name), __SIZEOF_POINTER__ 190END_MACRO 191 192MACRO1(END_FUNCTION, c_name) 193 CFI_ENDPROC 194 SIZE(SYMBOL(\c_name)) 195END_MACRO 196 197MACRO1(PUSH, reg) 198 pushq REG_VAR(reg) 199 CFI_ADJUST_CFA_OFFSET(8) 200 CFI_REL_OFFSET(REG_VAR(reg), 0) 201END_MACRO 202 203MACRO1(POP, reg) 204 popq REG_VAR(reg) 205 CFI_ADJUST_CFA_OFFSET(-8) 206 CFI_RESTORE(REG_VAR(reg)) 207END_MACRO 208 209// Arguments do not need .cfi_rel_offset as they are caller-saved and 210// therefore cannot hold caller's variables or unwinding data. 211MACRO1(PUSH_ARG, reg) 212 pushq REG_VAR(reg) 213 CFI_ADJUST_CFA_OFFSET(8) 214END_MACRO 215 216MACRO1(POP_ARG, reg) 217 popq REG_VAR(reg) 218 CFI_ADJUST_CFA_OFFSET(-8) 219END_MACRO 220 221MACRO3(SAVE_REG_BASE, base, reg, offset) 222 movq REG_VAR(reg), RAW_VAR(offset)(REG_VAR(base)) 223 CFI_REL_OFFSET(REG_VAR(reg), RAW_VAR(offset)) 224END_MACRO 225 226MACRO3(RESTORE_REG_BASE, base, reg, offset) 227 movq RAW_VAR(offset)(REG_VAR(base)), REG_VAR(reg) 228 CFI_RESTORE(REG_VAR(reg)) 229END_MACRO 230 231MACRO1(INCREASE_FRAME, frame_adjustment) 232 subq MACRO_LITERAL(RAW_VAR(frame_adjustment)), %rsp 233 CFI_ADJUST_CFA_OFFSET((RAW_VAR(frame_adjustment))) 234END_MACRO 235 236MACRO1(DECREASE_FRAME, frame_adjustment) 237 addq MACRO_LITERAL(RAW_VAR(frame_adjustment)), %rsp 238 CFI_ADJUST_CFA_OFFSET(-(RAW_VAR(frame_adjustment))) 239END_MACRO 240 241MACRO1(UNIMPLEMENTED,name) 242 FUNCTION_TYPE(SYMBOL(\name)) 243 ASM_HIDDEN VAR(name) 244 .globl VAR(name) 245 ALIGN_FUNCTION_ENTRY 246VAR(name): 247 CFI_STARTPROC 248 int3 249 int3 250 CFI_ENDPROC 251 SIZE(SYMBOL(\name)) 252END_MACRO 253 254MACRO0(UNREACHABLE) 255 int3 256END_MACRO 257 258MACRO0(UNTESTED) 259 int3 260END_MACRO 261 262MACRO1(LOAD_RUNTIME_INSTANCE, reg) 263 movq _ZN3art7Runtime9instance_E@GOTPCREL(%rip), REG_VAR(reg) 264 movq (REG_VAR(reg)), REG_VAR(reg) 265END_MACRO 266 267// Macros to poison (negate) the reference for heap poisoning. 268MACRO1(POISON_HEAP_REF, rRef) 269#ifdef USE_HEAP_POISONING 270 negl REG_VAR(rRef) 271#endif // USE_HEAP_POISONING 272END_MACRO 273 274// Macros to unpoison (negate) the reference for heap poisoning. 275MACRO1(UNPOISON_HEAP_REF, rRef) 276#ifdef USE_HEAP_POISONING 277 negl REG_VAR(rRef) 278#endif // USE_HEAP_POISONING 279END_MACRO 280 281 /* 282 * Macro that sets up the callee save frame to conform with 283 * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly) 284 */ 285MACRO0(SETUP_SAVE_REFS_ONLY_FRAME) 286#if defined(__APPLE__) 287 int3 288 int3 289#else 290 // R10 := Runtime::Current() 291 LOAD_RUNTIME_INSTANCE r10 292 // Save callee and GPR args, mixed together to agree with core spills bitmap. 293 PUSH r15 // Callee save. 294 PUSH r14 // Callee save. 295 PUSH r13 // Callee save. 296 PUSH r12 // Callee save. 297 PUSH rbp // Callee save. 298 PUSH rbx // Callee save. 299 // Create space for FPR args, plus space for ArtMethod*. 300 INCREASE_FRAME 8 + 4 * 8 301 // Save FPRs. 302 movq %xmm12, 8(%rsp) 303 movq %xmm13, 16(%rsp) 304 movq %xmm14, 24(%rsp) 305 movq %xmm15, 32(%rsp) 306 // R10 := ArtMethod* for refs only callee save frame method. 307 movq RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET(%r10), %r10 308 // Store ArtMethod* to bottom of stack. 309 movq %r10, 0(%rsp) 310 // Store rsp as the stop quick frame. 311 movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET 312 313 // Ugly compile-time check, but we only have the preprocessor. 314 // Last +8: implicit return address pushed on stack when caller made call. 315#if (FRAME_SIZE_SAVE_REFS_ONLY != 6 * 8 + 4 * 8 + 8 + 8) 316#error "FRAME_SIZE_SAVE_REFS_ONLY(X86_64) size not as expected." 317#endif 318#endif // __APPLE__ 319END_MACRO 320 321MACRO0(RESTORE_SAVE_REFS_ONLY_FRAME) 322 movq 8(%rsp), %xmm12 323 movq 16(%rsp), %xmm13 324 movq 24(%rsp), %xmm14 325 movq 32(%rsp), %xmm15 326 DECREASE_FRAME 8 + 4*8 327 // TODO: optimize by not restoring callee-saves restored by the ABI 328 POP rbx 329 POP rbp 330 POP r12 331 POP r13 332 POP r14 333 POP r15 334END_MACRO 335 336 /* 337 * Macro that sets up the callee save frame to conform with 338 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs), except for storing the method. 339 */ 340MACRO0(SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY) 341 // Save callee and GPR args, mixed together to agree with core spills bitmap. 342 PUSH r15 // Callee save. 343 PUSH r14 // Callee save. 344 PUSH r13 // Callee save. 345 PUSH r12 // Callee save. 346 PUSH_ARG r9 // Quick arg 5. 347 PUSH_ARG r8 // Quick arg 4. 348 PUSH_ARG rsi // Quick arg 1. 349 PUSH rbp // Callee save. 350 PUSH rbx // Callee save. 351 PUSH_ARG rdx // Quick arg 2. 352 PUSH_ARG rcx // Quick arg 3. 353 // Create space for FPR args and create 2 slots for ArtMethod*. 354 INCREASE_FRAME 16 + 12 * 8 355 // Save FPRs. 356 movq %xmm0, 16(%rsp) 357 movq %xmm1, 24(%rsp) 358 movq %xmm2, 32(%rsp) 359 movq %xmm3, 40(%rsp) 360 movq %xmm4, 48(%rsp) 361 movq %xmm5, 56(%rsp) 362 movq %xmm6, 64(%rsp) 363 movq %xmm7, 72(%rsp) 364 movq %xmm12, 80(%rsp) 365 movq %xmm13, 88(%rsp) 366 movq %xmm14, 96(%rsp) 367 movq %xmm15, 104(%rsp) 368 369 // Ugly compile-time check, but we only have the preprocessor. 370 // Last +8: implicit return address pushed on stack when caller made call. 371#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 11 * 8 + 12 * 8 + 16 + 8) 372#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(X86_64) size not as expected." 373#endif 374END_MACRO 375 376MACRO0(RESTORE_SAVE_REFS_AND_ARGS_FRAME) 377 // Restore FPRs. 378 movq 16(%rsp), %xmm0 379 movq 24(%rsp), %xmm1 380 movq 32(%rsp), %xmm2 381 movq 40(%rsp), %xmm3 382 movq 48(%rsp), %xmm4 383 movq 56(%rsp), %xmm5 384 movq 64(%rsp), %xmm6 385 movq 72(%rsp), %xmm7 386 movq 80(%rsp), %xmm12 387 movq 88(%rsp), %xmm13 388 movq 96(%rsp), %xmm14 389 movq 104(%rsp), %xmm15 390 DECREASE_FRAME 80 + 4 * 8 391 // Restore callee and GPR args, mixed together to agree with core spills bitmap. 392 POP_ARG rcx 393 POP_ARG rdx 394 POP rbx 395 POP rbp 396 POP_ARG rsi 397 POP_ARG r8 398 POP_ARG r9 399 POP r12 400 POP r13 401 POP r14 402 POP r15 403END_MACRO 404 405 /* 406 * Macro that sets up the callee save frame to conform with 407 * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves) 408 */ 409MACRO0(SETUP_SAVE_ALL_CALLEE_SAVES_FRAME) 410#if defined(__APPLE__) 411 int3 412 int3 413#else 414 // R10 := Runtime::Current() 415 LOAD_RUNTIME_INSTANCE r10 416 // Save callee save registers to agree with core spills bitmap. 417 PUSH r15 // Callee save. 418 PUSH r14 // Callee save. 419 PUSH r13 // Callee save. 420 PUSH r12 // Callee save. 421 PUSH rbp // Callee save. 422 PUSH rbx // Callee save. 423 // Create space for FPR args, plus space for ArtMethod*. 424 INCREASE_FRAME 4 * 8 + 8 425 // Save FPRs. 426 movq %xmm12, 8(%rsp) 427 movq %xmm13, 16(%rsp) 428 movq %xmm14, 24(%rsp) 429 movq %xmm15, 32(%rsp) 430 // R10 := ArtMethod* for save all callee save frame method. 431 movq RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET(%r10), %r10 432 // Store ArtMethod* to bottom of stack. 433 movq %r10, 0(%rsp) 434 // Store rsp as the top quick frame. 435 movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET 436 437 // Ugly compile-time check, but we only have the preprocessor. 438 // Last +8: implicit return address pushed on stack when caller made call. 439#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 6 * 8 + 4 * 8 + 8 + 8) 440#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(X86_64) size not as expected." 441#endif 442#endif // __APPLE__ 443END_MACRO 444 445MACRO0(SETUP_FP_CALLEE_SAVE_FRAME) 446 // Create space for ART FP callee-saved registers 447 INCREASE_FRAME 4 * 8 448 movq %xmm12, 0(%rsp) 449 movq %xmm13, 8(%rsp) 450 movq %xmm14, 16(%rsp) 451 movq %xmm15, 24(%rsp) 452END_MACRO 453 454MACRO0(RESTORE_FP_CALLEE_SAVE_FRAME) 455 // Restore ART FP callee-saved registers 456 movq 0(%rsp), %xmm12 457 movq 8(%rsp), %xmm13 458 movq 16(%rsp), %xmm14 459 movq 24(%rsp), %xmm15 460 DECREASE_FRAME 4 * 8 461END_MACRO 462 463 /* 464 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending 465 * exception is Thread::Current()->exception_ when the runtime method frame is ready. 466 */ 467MACRO0(DELIVER_PENDING_EXCEPTION_FRAME_READY) 468 // (Thread*) setup 469 movq %gs:THREAD_SELF_OFFSET, %rdi 470 call SYMBOL(artDeliverPendingExceptionFromCode) // artDeliverPendingExceptionFromCode(Thread*) 471 UNREACHABLE 472END_MACRO 473 /* 474 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending 475 * exception is Thread::Current()->exception_. 476 */ 477MACRO0(DELIVER_PENDING_EXCEPTION) 478 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save callee saves for throw 479 DELIVER_PENDING_EXCEPTION_FRAME_READY 480END_MACRO 481 482MACRO0(RETURN_OR_DELIVER_PENDING_EXCEPTION) 483 movq %gs:THREAD_EXCEPTION_OFFSET, %rcx // get exception field 484 testq %rcx, %rcx // rcx == 0 ? 485 jnz 1f // if rcx != 0 goto 1 486 ret // return 4871: // deliver exception on current thread 488 DELIVER_PENDING_EXCEPTION 489END_MACRO 490 491#endif // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_ 492