this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[mldr] Rewrite darling_thread_entry Inline Assembly

From the discussion in Discord, there are some strange/potentionally problematic design choices with the current inline assembly code.

To take advantage of the GNU register asm(...) feature, the std version need to be set to gnu11, instead of c11.

Thomas A c061846e 98c5c8ab

+67 -37
+1 -1
src/startup/CMakeLists.txt
··· 9 9 10 10 enable_language(C ASM) 11 11 12 - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -ggdb -O0") 12 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 -ggdb -O0") 13 13 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 14 14 #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Ttext-segment,0x400000 -Wl,-Tbss,0x410000 -Wl,-Tdata,0x420000") 15 15 add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" -D_GNU_SOURCE -DMLDR_BUILD)
+66 -36
src/startup/mldr/elfcalls/threads.c
··· 77 77 78 78 #define DEFAULT_DTHREAD_GUARD_SIZE 0x1000 79 79 80 + static inline void *align_16(uintptr_t ptr) { 81 + return (void *) ((uintptr_t) ptr & ~(uintptr_t) 15); 82 + } 83 + 80 84 static dthread_t dthread_structure_init(dthread_t dthread, size_t guard_size, void* stack_addr, size_t stack_size, void* base_addr, size_t total_size) { 81 85 // the pthread signature is the address of the pthread XORed with the "pointer munge" token passed in by the kernel 82 86 // since the LKM doesn't pass in a token, it's always zero, so the signature is equal to just the address ··· 250 254 return NULL; 251 255 } 252 256 257 + void *stack_ptr = align_16(args.stack_addr); 258 + 259 + // No additional function calls should occur beyond this point. Otherwise, we will risk our 260 + // registers being call-clobbered. I recommend reading the following doc for more details: 261 + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html 262 + #if __x86_64__ 263 + register void* arg1 asm("rdi") = args.pth; 264 + register int arg2 asm("esi") = args.port; 265 + register uintptr_t arg3 asm("rdx") = args.real_entry_point; 266 + register uintptr_t arg4 asm("rcx") = args.arg1; 267 + register uintptr_t arg5 asm("r8") = args.arg2; 268 + register uintptr_t arg6 asm("r9") = args.arg3; 269 + #elif __i386__ 270 + uintptr_t arg3 = args.real_entry_point; 271 + #endif 272 + 273 + if (arg3 == 0) { 274 + arg3 = (long) args.stack_bottom; 275 + } 276 + 253 277 #ifdef __x86_64__ 254 - __asm__ __volatile__ ( 255 - "movq %1, %%rdi\n" 256 - "movq 80(%0), %%rsp\n" 257 - "movq 40(%0), %%rsi\n" 258 - "movq 8(%0), %%rdx\n" 259 - "testq %%rdx, %%rdx\n" 260 - "jnz 1f\n" 261 - "movq 72(%0), %%rdx\n" // wqthread hack: if 3rd arg is null, we pass the stack bottom 262 - "1:\n" 263 - "movq 16(%0), %%rcx\n" 264 - "movq 24(%0), %%r8\n" 265 - "movq 32(%0), %%r9\n" 266 - "movq %%rdi, 56(%0)\n" 267 - "movq (%0), %%rax\n" 268 - "andq $-0x10, %%rsp\n" 269 - "pushq $0\n" 270 - "pushq $0\n" 271 - "jmpq *%%rax\n" 272 - :: "a" (&args), "di" (args.pth)); 278 + asm volatile( 279 + // Zero out the frame base register. 280 + "xorq %%rbp, %%rbp\n" 281 + // Switch to the new stack. 282 + "movq %[stack_ptr], %%rsp\n" 283 + // Push a fake return address. 284 + "pushq $0\n" 285 + // Jump to the entry point. 286 + "jmp *%[entry_point]" :: 287 + 288 + // Function arguments 289 + "r"(arg1),"r"(arg2),"r"(arg3),"r"(arg4),"r"(arg5),"r"(arg6), 290 + 291 + [entry_point] "r"(args.entry_point), 292 + [stack_ptr] "r"(stack_ptr) 293 + ); 273 294 #elif defined(__i386__) // args in eax, ebx, ecx, edx, edi, esi 274 295 __asm__ __volatile__ ( 275 - "movl (%0), %%eax\n" 276 - "movl 40(%0), %%esp\n" 277 - "pushl %%eax\n" // address to be jumped to 278 - "movl %1, 28(%0)\n" 279 - "movl %1, %%eax\n" // 1st arg 280 - "movl 20(%0), %%ebx\n" // 2nd arg 281 - "movl 8(%0), %%edx\n" // 4th arg 282 - "movl 12(%0), %%edi\n" // 5th arg 283 - "movl 16(%0), %%esi\n" // 6th arg 284 - "movl 4(%0), %%ecx\n" // 3rd arg 285 - "testl %%ecx, %%ecx\n" // FIXME: clobbered ecx! 286 - "jnz 1f\n" 287 - "movl 36(%0), %%ecx\n" // if the 3rd argument is null, pass the stack bottom 288 - "1:\n" 289 - "ret\n" // Jump to the address pushed at the beginning 290 - :: "c" (&args), "d" (args.pth)); 296 + // Zero out the frame base register. 297 + "xorl %%ebp, %%ebp\n" 298 + // Switch to the new stack. 299 + "movl %[stack_ptr], %%esp\n" 300 + // Make sure stack is 16 aligned (before we push the fake return address) 301 + "sub $8, %%esp\n" 302 + // Unlike x86_64, all function arguments must be stored in the stack 303 + "pushl 16(%[args])\n" // 6th argument | args.arg3 304 + "pushl 12(%[args])\n" // 5th argument | args.arg2 305 + "pushl 8(%[args])\n" // 4th argument | args.arg1 306 + "pushl %[arg3]\n" // 3rd argument | args3 307 + "pushl 20(%[args])\n" // 2nd argument | args.port 308 + "pushl 28(%[args])\n" // 1st argument | args.pth 309 + // Push a fake return address. 310 + "pushl $0\n" 311 + // Jump to the entry point. 312 + "jmp *%[entry_point]" :: 313 + 314 + // Function arguments to push to the stack. 315 + [args] "r"(&args), [arg3]"r"(arg3), 316 + 317 + [entry_point] "r"(args.entry_point), 318 + [stack_ptr] "r"(stack_ptr) 319 + ); 291 320 #else 292 - #error Not implemented 321 + #error Not implemented 322 + // args.entry_point(args.pth, args.port, args.real_entry_point, args.arg1, args.arg2, args.arg3); 293 323 #endif 294 324 __builtin_unreachable(); 295 325 }