diff options
Diffstat (limited to 'src/llvm_backend_proc.cpp')
| -rw-r--r-- | src/llvm_backend_proc.cpp | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index f7298a4a6..8b9f8b249 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2660,10 +2660,26 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu { GB_ASSERT(arg_count <= 7); + // FreeBSD additionally clobbers r8, r9, r10, but they + // can also be used to pass in arguments, so this needs + // to be handled in two parts. + bool clobber_arg_regs[7] = { + false, false, false, false, false, false, false + }; + if (build_context.metrics.os == TargetOs_freebsd) { + clobber_arg_regs[4] = true; // r10 + clobber_arg_regs[5] = true; // r8 + clobber_arg_regs[6] = true; // r9 + } + char asm_string[] = "syscall"; gbString constraints = gb_string_make(heap_allocator(), "={rax}"); for (unsigned i = 0; i < arg_count; i++) { - constraints = gb_string_appendc(constraints, ",{"); + if (!clobber_arg_regs[i]) { + constraints = gb_string_appendc(constraints, ",{"); + } else { + constraints = gb_string_appendc(constraints, ",+{"); + } static char const *regs[] = { "rax", "rdi", @@ -2687,10 +2703,35 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu // Some but not all system calls will additionally // clobber memory. // - // TODO: FreeBSD is different and will also clobber - // R8, R9, and R10. Additionally CF is used to - // indicate an error instead of -errno. + // As a fix for CVE-2019-5595, FreeBSD started + // clobbering R8, R9, and R10, instead of restoring + // them. Additionally unlike Linux, instead of + // returning negative errno, positive errno is + // returned and CF is set. + // + // TODO: + // * Figure out what Darwin does. + // * Add some extra handling to propagate CF back + // up to the caller on FreeBSD systems so that + // the caller knows that the return value is + // positive errno. constraints = gb_string_appendc(constraints, ",~{rcx},~{r11},~{memory}"); + if (build_context.metrics.os == TargetOs_freebsd) { + // Second half of dealing with FreeBSD's system + // call semantics. Explicitly clobber the registers + // that were not used to pass in arguments, and + // then clobber RFLAGS. + if (arg_count < 5) { + constraints = gb_string_appendc(constraints, ",~{r10}"); + } + if (arg_count < 6) { + constraints = gb_string_appendc(constraints, ",~{r8}"); + } + if (arg_count < 7) { + constraints = gb_string_appendc(constraints, ",~{r9}"); + } + constraints = gb_string_appendc(constraints, ",~{cc}"); + } inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } |