this repo has no description
at fixPythonPipStalling 354 lines 8.7 kB view raw
1#include <functional> 2#include <stdint.h> 3#include <iostream> 4#include <type_traits> 5#include <stdexcept> 6#include <vector> 7#include <string> 8 9struct AssemblyString 10{ 11 std::string name; 12 std::string value; 13}; 14static std::vector<AssemblyString> _strings; 15 16template <typename Retval> 17void handle_retval() { std::cout << "\t// retval - nop (void or 4-byte integer)\n"; } 18 19template <> void handle_retval<long long>() 20{ 21 std::cout << "\t// retval - 8-byte integer\n" 22 "\tmovq %rax, %rdx\n" 23 "\tshrq $32, %rdx\n"; // place upper 32-bits into edx 24 std::cout << "\t// end retval\n"; 25} 26template <> void handle_retval<void*>() { handle_retval<long long>(); } 27template <> void handle_retval<unsigned long long>() { handle_retval<long long>(); } 28 29class Context 30{ 31public: 32 Context(const char* name) 33 : _name(name) 34 { 35 } 36 37 bool has_int_registers_left() const 38 { 39 return _int_count < 6; 40 } 41 42 const char* next_int_register(bool _32bit = false) 43 { 44 if (!has_int_registers_left()) 45 throw std::logic_error("No registers left"); 46 47 const char* ARGUMENT_REGS[] = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; 48 const char* ARGUMENT_REGS32[] = { "%edi", "%esi", "%edx", "%ecx", "%r8", "%r9" }; 49 return _32bit ? ARGUMENT_REGS32[_int_count++] : ARGUMENT_REGS[_int_count++]; 50 } 51 52 bool has_fp_registers_left() const 53 { 54 return _fp_count < 8; 55 } 56 57 const char* next_fp_register() 58 { 59 if (!has_fp_registers_left()) 60 throw std::logic_error("No fp registers left"); 61 62 const char* FP_ARGUMENT_REGS[] = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" }; 63 return FP_ARGUMENT_REGS[_fp_count++]; 64 } 65 66 int esp_advance(int how_much) 67 { 68 int rv = _esp_offset; 69 _esp_offset += how_much; 70 return rv; 71 } 72 73 int next_int_stack_offset() 74 { 75 if (has_int_registers_left()) 76 throw std::logic_error("Registers are still left"); 77 78 int offset = (_int_count-6) * 8; 79 offset += std::max(0, (_fp_count-8) * 16); 80 81 _int_count++; 82 return offset; 83 } 84 85 int next_fp_stack_offset() 86 { 87 if (has_fp_registers_left()) 88 throw std::logic_error("FP registers are still left"); 89 90 int offset = (_fp_count-8) * 16; 91 offset += std::max(0, (_int_count-6) * 8); 92 93 _fp_count++; 94 return offset; 95 } 96 97protected: 98 const char* _name; 99 // Next offset in 32-bit argument stack 100 int _esp_offset = 4; 101 // How many integer arguments have been converted so far 102 int _int_count = 0; 103 // How many floating point arguments have been converted so far 104 int _fp_count = 0; 105}; 106 107template <typename Argtype> 108 void copy_argument(Context& ctxt) 109{ 110 std::cout << "\tmovl " << ctxt.esp_advance(4) << "(%rsp), " << ctxt.next_int_register(true) << std::endl; 111} 112 113template <> 114 void copy_argument<long long>(Context& ctxt) 115{ 116 std::cout << "\tmovq " << ctxt.esp_advance(8) << "(%rsp), " << ctxt.next_int_register() << std::endl; 117} 118 119template <typename Argtype> void count_argument(int& ints, int& fps) { ints++; } 120template <> void count_argument<float>(int& ints, int& fps) { fps++; } 121template <> void count_argument<double>(int& ints, int& fps) { fps++; } 122 123template <typename ...Args> 124class handle_arguments; 125 126template <> 127class handle_arguments<> 128{ 129public: 130 static void generate(Context& context, int index = 0) 131 { 132 } 133 134 static void count(int& ints, int& fps) 135 { 136 } 137}; 138 139template <typename Arg0, typename ...Args> 140class handle_arguments<Arg0, Args...> 141{ 142public: 143 static void generate(Context& ctxt, int index = 0) 144 { 145 std::cout << "\t// argument #" << index << "\n"; 146 copy_argument<Arg0>(ctxt); 147 handle_arguments<Args...>::generate(ctxt, index+1); 148 } 149 150 static void count(int& ints, int& fps) 151 { 152 count_argument<Arg0>(ints, fps); 153 handle_arguments<Args...>::count(ints, fps); 154 } 155}; 156 157template <typename Retval, typename ...Args> 158class Stubifier; 159 160template <typename Retval, typename ...Args> 161class Stubifier<Retval(Args...)> : public Context 162{ 163public: 164 Stubifier(const char* name) 165 : Context(name) 166 { 167 } 168 169 void generate() 170 { 171 int stackalign = 4; // for return address of the call to this stub 172 int ints = 0, fps = 0; 173 174 _strings.push_back(AssemblyString{ std::string("_name_") + _name, _name }); 175 176 std::cout << ".globl _" << _name << "\n_" 177 << _name << ":\n" 178 "\tprologue\n"; 179 180 std::cout << "\t// Get real implementation\n"; 181 std::cout << "\tmovq _" << _name << "_impl(%rip), %r10\n"; 182 std::cout << "\ttestq %r10, %r10\n" 183 "\tjnz 1f\n" 184 "\tloadfunc _name_" << _name << ", _" << _name << "_impl\n"; 185 186 std::cout << "1:\n"; 187 handle_arguments<Args...>::count(ints, fps); 188 189 if (ints >= 1) 190 { 191 stackalign += 4; // calee save edi 192 if (ints >= 2) 193 { 194 stackalign += 4; // calee save esi 195 if (ints > 6) 196 stackalign += (ints-6) * 8; 197 } 198 } 199 if (fps > 8) 200 stackalign += (fps-8) * 16; 201 202 // The stack must be 16-byte aligned 203 stackalign = (stackalign + 15) / 16; 204 stackalign *= 16; 205 stackalign -= 4; // subtract the 4 bytes we had from the start 206 207 // Arguments on the stack are now farther away 208 _esp_offset += stackalign; 209 210 std::cout << "\t// shift stack for alignment and/or extra stuff on stack\n"; 211 std::cout << "\tsubq $" << stackalign << ", %rsp\n"; 212 213 // esi and edi are calee save 214 if (ints >= 1) 215 { 216 std::cout << "\t// calee save registers\n"; 217 std::cout << "\tmovl %edi, " << stackalign-4 << "(%rsp)\n"; 218 if (ints >= 2) 219 std::cout << "\tmovl %esi, " << stackalign-8 << "(%rsp)\n"; 220 } 221 222 handle_arguments<Args...>::generate(*this); 223 224 // call the implementation 225 std::cout << "\t// call the implementation\n" 226 "\tcallq *%r10\n"; 227 228 handle_retval<Retval>(); 229 230 // restore edi and esi 231 if (ints >= 1) 232 { 233 std::cout << "\t// restore calee save registers\n"; 234 if (ints >= 2) 235 std::cout << "\tmovl " << stackalign-8 << "(%rsp), %esi\n"; 236 std::cout << "\tmovl " << stackalign-4 << "(%rsp), %edi\n"; 237 } 238 239 std::cout << "\taddq $" << stackalign << ", %rsp\n"; 240 241 std::cout << "\tepilogue\n" 242 "// end of " << _name << "\n\n"; 243 std::cout << ".zerofill __DATA,__bss,_" << _name << "_impl,8,3\n"; 244 } 245 246}; 247 248void print_init() 249{ 250 std::cout << ".zerofill __DATA,__bss,_lib_handle,8,3\n"; 251 252 std::cout << ".code64\n"; 253 std::cout << "_initializer:\n" 254 "\tpushq %rdi\n" 255 "\tmovq L__darling_elfcalls$non_lazy_ptr(%rip), %rax\n" 256 "\tmovq (%rax), %rax\n" 257 "\tmovq _library_name(%rip), %rdi\n" 258 "\tcallq *(%rax)\n" 259 "\tmovq %rax, _lib_handle(%rip)\n" 260 "\tpopq %rdi\n" 261 "\tret\n\n"; 262 263 std::cout << "_destructor:\n" 264 "\tpushq %rdi\n" 265 "\tmovq L__darling_elfcalls$non_lazy_ptr(%rip), %rcx\n" 266 "\tmovq (%rcx), %rcx\n" 267 "\tmovq _lib_handle(%rip), %rdi\n" 268 "\tcallq *8(%rcx)\n" 269 "\tpopq %rdi\n" 270 "\tret\n\n"; 271 272 std::cout << ".code32\n"; 273 std::cout << ".section __DATA,__mod_init_func,mod_init_funcs\n" 274 ".align 2\n" 275 ".long _initializer\n" 276 ".section __DATA,__mod_term_func,mod_term_funcs\n" 277 ".align 2\n" 278 ".long _destructor\n\n"; 279} 280 281#define STUBIFY(name) Stubifier<decltype(name)>(#name).generate() 282 283void produce_stubs(); 284extern const char* library_name; 285 286int main() 287{ 288 _strings.push_back(AssemblyString{ "_library_name", library_name }); 289 290 std::cout << ".section __TEXT,__text,regular,pure_instructions\n\n"; 291 292 std::cout << ".macro prologue\n" 293 "\tsubl $$8, %esp\n" 294 "\tmovl $$0x33, 4(%esp)\n" 295 "\tleal 2f, %eax\n" 296 "\tmovl %eax, (%esp)\n" 297 "\tlret\n" 298 /* Now in 64-bit mode */ 299 "2:\n" \ 300 ".code64\n" \ 301 ".endmacro\n\n"; 302 303 std::cout << ".macro epilogue\n" 304 /* Transition 64->32 */ 305 "\tsubq $$8, %rsp\n" 306 "\tleaq 3f, %rcx\n" 307 "\tmovl $$0x23, 4(%rsp)\n" 308 "\tmovl %ecx, (%rsp)\n" 309 "\tlret\n" 310 "3:\n" 311 ".code32\n" 312 "\tpush $$0x2b\n" 313 "\tpop %ds\n" 314 "\tret\n" 315 ".endmacro\n\n"; 316 317 std::cout << ".macro loadfunc\n" 318 "\tpushq %rdi\n" 319 "\tpushq %rsi\n" 320 "\tmovq _lib_handle(%rip), %rdi\n" 321 "\tmovq $0(%rip), %rsi\n" 322 "\tmovq L__darling_elfcalls$$non_lazy_ptr(%rip), %rax\n" 323 "\tmovq (%rax), %rax\n" 324 "\tcallq *16(%rax)\n" 325 "\tmovq %rax, $1\n" 326 "\tmovq %rax, %r10\n" 327 "\tpopq %rsi\n" 328 "\tpopq %rdi\n" 329 ".endmacro\n\n"; 330 331 print_init(); 332 produce_stubs(); 333 334 std::cout << ".section __TEXT,__cstring,cstring_literals\n"; 335 for (const AssemblyString& str : _strings) 336 { 337 std::cout << "L_." << str.name.c_str() << ": .asciz \"" << str.value.c_str() << "\"\n"; 338 std::cout << str.name.c_str() << ": .long L_." << str.name.c_str() << std::endl; 339 } 340 std::cout << std::endl; 341 342 std::cout << ".section __IMPORT,__pointers,non_lazy_symbol_pointers\n" 343 "L__darling_elfcalls$non_lazy_ptr:\n" 344 ".indirect_symbol __darling_elfcalls\n" 345 ".long 0\n\n"; 346 347 std::cout << ".subsections_via_symbols\n\n"; 348 349 return 0; 350} 351 352#include "produce_stubs.h" 353 354