Search code examples
clinkertcc

Why doesn't TCC generate my custom section?


I have a small C program:

#include <stdio.h>

struct foo {
  int x;
  struct foo *next;
};

#define CONST __attribute__((used, section("const_heap")))

struct foo f CONST = { 1, 0 };
struct foo g CONST = { 2, &g };

extern char *__start_const_heap;
extern char *__stop_const_heap;

int main() {
  printf("f: %p, g: %p\n", &f, &g);
  printf("start: %p, end %p\n", &__start_const_heap, &__stop_const_heap);
}

and I want to be able to check if a pointer is within a section const_heap. GCC and Clang compile and run this fine; TCC has a linker error for the __start and __stop symbols.

hickory% gcc const.c && ./a.out
f: 0x5c97a966d020, g: 0x5c97a966d030
start: 0x5c97a966d048, end 0x5c97a966d050
hickory% clang const.c && ./a.out
f: 0x574924409030, g: 0x574924409040
start: 0x574924409068, end 0x574924409070
hickory% tcc const.c
tcc: error: undefined symbol '__stop_const_heap'
tcc: error: undefined symbol '__start_const_heap'
hickory%

(the exact numbers don't matter; just that the program runs and prints a pointer)

I checked with readelf on the (unlinked) object file and sure enough, no const_heap section is present.

TCC apparently supports this as of 0.9.9 and I am using 0.9.27 (20-some years newer). Even the TCC code looks like this should work. What am I doing wrong?

EDIT: Just downloaded and compiled the latest commit and it still fails with the same error.


Solution

  • preprocessor makes attributes disappear:

    Yes, you stumbled over an artifact of the glibc standard headers. If used with a compiler that doesn't claim to be GCC (e.g. with TCC), you'll hit this snippet in /usr/include/sys/cdefs.h:

        #if !defined __GNUC__ || __GNUC__ < 2
        # define __attribute__(xyz)     /* Ignore */
        #endif
    

    With this tweak it works on all 3 compilers:

    #include <stdio.h>
    #if !defined __GNUC__ || __GNUC__ < 2
    #undef __attribute__
    #endif
    
    struct foo {
      int x;
      struct foo *next;
    };
    
    #define CONST __attribute__((section("const_heap")))
    
    struct foo f CONST = { 1, 0 };
    struct foo g CONST = { 2, &g };
    
    extern char *__start_const_heap;
    extern char *__stop_const_heap;
    
    int main() {
      printf("f: %p, g: %p\n", &f, &g);
      printf("start: %p, end %p\n", &__start_const_heap, &__stop_const_heap);
    }