1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// 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
|