From 671dcace82debc4548029ff4fcc1a7f4db6d05e6 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Fri, 6 Apr 2018 23:01:45 +0200 Subject: [PATCH] Implement function alignment via attributes which requires being able to emit an arbitrary number of NOP instructions, which is also implemented here. For x86 we could emit other sequences but these are the easiest. --- arm-gen.c | 10 ++++++++++ arm64-gen.c | 10 ++++++++++ c67-gen.c | 10 ++++++++++ i386-gen.c | 6 ++++++ tcc.h | 1 + tccgen.c | 7 +++++++ tests/tcctest.c | 6 ++++++ x86_64-gen.c | 6 ++++++ 8 files changed, 56 insertions(+) diff --git a/arm-gen.c b/arm-gen.c index f535a09..634cffb 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -1410,6 +1410,16 @@ void gfunc_epilog(void) } } +ST_FUNC void gen_fill_nops(int bytes) +{ + if ((bytes & 3)) + tcc_error("alignment of code section not multiple of 4"); + while (bytes > 0) { + o(0xE1A00000); + bytes -= 4; + } +} + /* generate a jump to a label */ int gjmp(int t) { diff --git a/arm64-gen.c b/arm64-gen.c index 86b3af7..26cf5d1 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -1276,6 +1276,16 @@ ST_FUNC void gfunc_epilog(void) o(0xd65f03c0); // ret } +ST_FUNC void gen_fill_nops(int bytes) +{ + if ((bytes & 3)) + tcc_error("alignment of code section not multiple of 4"); + while (bytes > 0) { + o(0xd503201f); // nop + bytes -= 4; + } +} + // Generate forward branch to label: ST_FUNC int gjmp(int t) { diff --git a/c67-gen.c b/c67-gen.c index bcb4b0e..d21626a 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -2035,6 +2035,16 @@ void gfunc_epilog(void) } } +ST_FUNC void gen_fill_nops(int bytes) +{ + if ((bytes & 3)) + tcc_error("alignment of code section not multiple of 4"); + while (bytes > 0) { + C67_NOP(4); + bytes -= 4; + } +} + /* generate a jump to a label */ int gjmp(int t) { diff --git a/i386-gen.c b/i386-gen.c index b9c3599..b6629d4 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -157,6 +157,12 @@ static int oad(int c, int s) return t; } +ST_FUNC void gen_fill_nops(int bytes) +{ + while (bytes--) + g(0x90); +} + /* generate jmp to a label */ #define gjmp2(instr,lbl) oad(instr,lbl) diff --git a/tcc.h b/tcc.h index cd67973..c2aaa42 100644 --- a/tcc.h +++ b/tcc.h @@ -1475,6 +1475,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *reg ST_FUNC void gfunc_call(int nb_args); ST_FUNC void gfunc_prolog(CType *func_type); ST_FUNC void gfunc_epilog(void); +ST_FUNC void gen_fill_nops(int); ST_FUNC int gjmp(int t); ST_FUNC void gjmp_addr(int a); ST_FUNC int gtst(int inv, int t); diff --git a/tccgen.c b/tccgen.c index 6ef40e4..4f2e68b 100644 --- a/tccgen.c +++ b/tccgen.c @@ -7088,6 +7088,13 @@ static void gen_function(Sym *sym) { nocode_wanted = 0; ind = cur_text_section->data_offset; + if (sym->a.aligned) { + size_t newoff = section_add(cur_text_section, 0, + 1 << (sym->a.aligned - 1)); + if (ind != newoff) + gen_fill_nops(newoff - ind); + ind = newoff; + } /* NOTE: we patch the symbol size later */ put_extern_sym(sym, cur_text_section, ind, 0); funcname = get_tok_str(sym->v, NULL); diff --git a/tests/tcctest.c b/tests/tcctest.c index 56d51dc..3dc9f1d 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -2270,6 +2270,8 @@ int fib(int n) return fib(n-1) + fib(n-2); } +void __attribute__((aligned(16))) aligned_function(int i) {} + void funcptr_test() { void (*func)(int); @@ -2300,6 +2302,10 @@ void funcptr_test() func(42); (func + diff)(42); (num + a)(43); + + /* Check that we can align functions */ + func = aligned_function; + printf("aligned_function (should be zero): %d\n", ((int)func) & 15); } void lloptest(long long a, long long b) diff --git a/x86_64-gen.c b/x86_64-gen.c index e33a38a..9ca5c11 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1639,6 +1639,12 @@ void gfunc_epilog(void) #endif /* not PE */ +ST_FUNC void gen_fill_nops(int bytes) +{ + while (bytes--) + g(0x90); +} + /* generate a jump to a label */ int gjmp(int t) {