diff --git a/tccgen.c b/tccgen.c index f183913..f79da36 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3665,20 +3665,23 @@ ST_FUNC void unary(void) break; case TOK_builtin_frame_address: { + int level; CType type; next(); skip('('); - if (tok != TOK_CINT) { - tcc_error("__builtin_frame_address only takes integers"); - } - if (tokc.i != 0) { - tcc_error("TCC only supports __builtin_frame_address(0)"); + if (tok != TOK_CINT || tokc.i < 0) { + tcc_error("__builtin_frame_address only takes positive integers"); } + level = tokc.i; next(); skip(')'); type.t = VT_VOID; mk_pointer(&type); - vset(&type, VT_LOCAL, 0); + vset(&type, VT_LOCAL, 0); /* local frame */ + while (level--) { + mk_pointer(&vtop->type); + indir(); /* -> parent frame */ + } } break; #ifdef TCC_TARGET_X86_64 diff --git a/tests/Makefile b/tests/Makefile index 2e7dd23..af1fdb8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -73,7 +73,7 @@ libtcc_test$(EXESUF): libtcc_test.c ../$(LIBTCC) # copy only tcclib.h so GCC's stddef and stdarg will be used test.ref: tcctest.c cp ../include/tcclib.h . - $(CC) -o tcctest.gcc $< -I. $(CPPFLAGS) -w $(CFLAGS) $(NATIVE_DEFINES) -std=gnu99 $(LDFLAGS) + $(CC) -o tcctest.gcc $< -I. $(CPPFLAGS) -w $(CFLAGS) $(NATIVE_DEFINES) -std=gnu99 -O0 -fno-omit-frame-pointer $(LDFLAGS) ./tcctest.gcc > $@ # auto test diff --git a/tests/tcctest.c b/tests/tcctest.c index 82762ea..4f9f2a3 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -89,6 +89,7 @@ void global_data_test(void); void cmp_comparison_test(void); void math_cmp_test(void); void callsave_test(void); +void builtin_frame_address_test(void); int fib(int n); void num(int n); @@ -598,6 +599,7 @@ int main(int argc, char **argv) cmp_comparison_test(); math_cmp_test(); callsave_test(); + builtin_frame_address_test(); return 0; } @@ -2680,3 +2682,28 @@ void callsave_test(void) printf ("%d\n", i); #endif } + + +void bfa3(ptrdiff_t str_offset) +{ + printf("bfa3: %s\n", (char *)__builtin_frame_address(3) + str_offset); +} +void bfa2(ptrdiff_t str_offset) +{ + printf("bfa2: %s\n", (char *)__builtin_frame_address(2) + str_offset); + bfa3(str_offset); +} +void bfa1(ptrdiff_t str_offset) +{ + printf("bfa1: %s\n", (char *)__builtin_frame_address(1) + str_offset); + bfa2(str_offset); +} + +void builtin_frame_address_test(void) +{ + char str[] = "__builtin_frame_address"; + char *fp0 = __builtin_frame_address(0); + + printf("str: %s\n", str); + bfa1(str-fp0); +}