Browse Source

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.
Michael Matz 1 year ago
parent
commit
671dcace82
8 changed files with 56 additions and 0 deletions
  1. 10 0
      arm-gen.c
  2. 10 0
      arm64-gen.c
  3. 10 0
      c67-gen.c
  4. 6 0
      i386-gen.c
  5. 1 0
      tcc.h
  6. 7 0
      tccgen.c
  7. 6 0
      tests/tcctest.c
  8. 6 0
      x86_64-gen.c

+ 10 - 0
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)
 {

+ 10 - 0
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)
 {

+ 10 - 0
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)
 {

+ 6 - 0
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)
 

+ 1 - 0
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);

+ 7 - 0
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);

+ 6 - 0
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)

+ 6 - 0
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)
 {