// REQUIRES: x86-registered-target // This verifies that global variable redirection works correctly when using hotpatching. // // RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 \ // RUN: -fms-secure-hotpatch-functions-list=hp1,hp2,hp3,hp4,hp5_phi_ptr_mixed,hp_phi_ptr_both,hp_const_ptr_sub \ // RUN: /clang:-S /clang:-o- -- %s | FileCheck %s #ifdef __clang__ #define NO_TAIL __attribute__((disable_tail_calls)) #else #define NO_TAIL #endif extern int g_data[10]; struct SomeData { int x; int y; }; const struct SomeData g_this_is_const = { 100, 200 }; struct HasPointers { int* ptr; int x; }; extern struct HasPointers g_has_pointers; void take_data(const void* p); void do_side_effects(); void do_other_side_effects(); void hp1() NO_TAIL { take_data(&g_data[5]); } // CHECK: hp1: // CHECK: mov rcx, qword ptr [rip + __ref_g_data] // CHECK: add rcx, 20 // CHECK: call take_data // CHECK: .seh_endproc void hp2() NO_TAIL { // We do not expect string literals to be redirected. take_data("hello, world!"); } // CHECK: hp2: // CHECK: lea rcx, [rip + "??_C@_0O@KJBLMJCB@hello?0?5world?$CB?$AA@"] // CHECK: call take_data // CHECK: .seh_endproc void hp3() NO_TAIL { // We do not expect g_this_is_const to be redirected because it is const // and contains no pointers. take_data(&g_this_is_const); } // CHECK: hp3: // CHECK: lea rcx, [rip + g_this_is_const] // CHECK: call take_data // CHECK-NOT: __ref_g_this_is_const // CHECK: .seh_endproc void hp4() NO_TAIL { take_data(&g_has_pointers); // We expect &g_has_pointers to be redirected. } // CHECK: hp4: // CHECK: mov rcx, qword ptr [rip + __ref_g_has_pointers] // CHECK: call take_data // CHECK: .seh_endproc // This case checks that global variable redirection interacts correctly with PHI nodes. // The IR for this generates a "phi ptr g_has_pointers, g_this_is_const" node. // We expect g_has_pointers to be redirected, but not g_this_is_const. void hp5_phi_ptr_mixed(int x) NO_TAIL { const void* y; if (x) { y = &g_has_pointers; do_side_effects(); } else { y = &g_this_is_const; do_other_side_effects(); } take_data(y); } // CHECK: hp5_phi_ptr_mixed // CHECK: .seh_endprologue // CHECK: test ecx, ecx // CHECK: mov rsi, qword ptr [rip + __ref_g_has_pointers] // CHECK: call do_side_effects // CHECK: jmp // CHECK: call do_other_side_effects // CHECK: lea rsi, [rip + g_this_is_const] // CHECK: mov rcx, rsi // CHECK: call take_data // CHECK: .seh_endproc // This case tests that global variable redirection interacts correctly with PHI nodes, // where two (all) operands of a given PHI node are globabl variables that redirect. void hp_phi_ptr_both(int x) NO_TAIL { const void* y; if (x) { y = &g_has_pointers; do_side_effects(); } else { y = &g_data[5]; do_other_side_effects(); } take_data(y); } // CHECK: hp_phi_ptr_both: // CHECK: .seh_endprologue // CHECK: test ecx, ecx // CHECK: mov rsi, qword ptr [rip + __ref_g_has_pointers] // CHECK: mov rsi, qword ptr [rip + __ref_g_data] // CHECK: take_data // CHECK: .seh_endproc // Test a constant expression which references global variable addresses. size_t hp_const_ptr_sub() NO_TAIL { return (unsigned char*)&g_has_pointers - (unsigned char*)&g_data; } // CHECK: hp_const_ptr_sub: // CHECK: mov rax, qword ptr [rip + __ref_g_has_pointers] // CHECK: sub rax, qword ptr [rip + __ref_g_data] // CHECK: ret