From e4d874d88a2ef874a9c2fd7c47d3d3a35ae986e2 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Tue, 30 Jul 2024 10:33:44 -0400 Subject: [PATCH] fix: code in non-executable ELF sections --- tccasm.c | 3 +++ tccgen.c | 1 + tests/exec_section_in_asm.c | 28 ++++++++++++++++++++++++++++ tests/exec_section_in_c.c | 13 +++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 tests/exec_section_in_asm.c create mode 100644 tests/exec_section_in_c.c diff --git a/tccasm.c b/tccasm.c index d056c7031..a75661e44 100644 --- a/tccasm.c +++ b/tccasm.c @@ -893,6 +893,9 @@ static void asm_parse_directive(TCCState *s1, int global) if (old_nb_section != s1->nb_sections) cur_text_section->sh_addralign = 1; } + /* The section directive supports flags, but they are unsupported. + For now, just assume any section contains code. */ + cur_text_section->sh_flags |= SHF_EXECINSTR; break; case TOK_ASMDIR_previous: { diff --git a/tccgen.c b/tccgen.c index a1c7db473..57bc493f2 100644 --- a/tccgen.c +++ b/tccgen.c @@ -8303,6 +8303,7 @@ static void gen_function(Sym *sym) cur_scope = root_scope = &f; nocode_wanted = 0; + cur_text_section->sh_flags |= SHF_EXECINSTR; ind = cur_text_section->data_offset; if (sym->a.aligned) { size_t newoff = section_add(cur_text_section, 0, diff --git a/tests/exec_section_in_asm.c b/tests/exec_section_in_asm.c new file mode 100644 index 000000000..8f13a418c --- /dev/null +++ b/tests/exec_section_in_asm.c @@ -0,0 +1,28 @@ +/* Previously in TinyCC, ELF sections defined in assembly would always have the +execute bit not set, so you would get segmentation faults when code in these +sections was exectuted. This file is a minimal example of a file that will put +the resulting code in a non-executable section (and invoke it) prior to the fix. +*/ +#include + +void *memset(void *dst, int c, int len); + +__asm__ ( +".section .text.nolibc_memset\n" +".weak memset\n" +"memset:\n" + "xchgl %eax, %esi\n\t" + "movq %rdx, %rcx\n\t" + "pushq %rdi\n\t" + "rep stosb\n\t" + "popq %rax\n\t" + "retq\n" +); + +int main () { + char buf[10]; + memset(&buf[0], 'A', 9); + buf[9] = 0; + puts(buf); + return 0; +} diff --git a/tests/exec_section_in_c.c b/tests/exec_section_in_c.c new file mode 100644 index 000000000..8a6fbac39 --- /dev/null +++ b/tests/exec_section_in_c.c @@ -0,0 +1,13 @@ +/* Previously in TinyCC, ELF sections defined in attributes would always have +the execute bit not set, so you would get segmentation faults when code in these +sections was exectuted. This file is a minimal example of a file that will put +the resulting code in a non-executable section (and invoke it) prior to the fix. +*/ +__attribute__((section(".text.wumbo"))) +int wumbo (int arg) { + return arg * 2; +} + +int main () { + return wumbo(2); +}