I suppose the error is saying that R_X86_64_PC32 "can not be used when making a shared object". That is, I assume that you are trying to avoid PIC at the moment. Regretfully, I can not offer solution, but I can offer some insight. From your post I understand that your loader for libc cannot handle relocations. Otherwise you could coerce the linker by compiling with "-mcmodel=large". The result would use 64 bit memory references, turning the R_X86_64_PC32 relocations to type R_X86_64_64. The current complaint of the linker is that the modules may span more than 4 gigs and patching some of the relocations at load time may be impossible, but with 64-bit relocations this is not a problem. However, if your early-phase loader cannot apply relocations, this is not what you want. Just in case,
here is some information on the subject.
You may ask, why do you need the relocations here to begin with? There are two features in Unix that necessitate relocatable self-references in libraries. Those features, with all their caveats and shortcomings, are copy relocations and resolution of symbols according to load order precedence. With load ordering, you can hook or override the calls of a library by providing identical exports in another library or the main executable. For example, a program can substitute the malloc allocator, overriding the default one exported by libc. All modules in that process will use the new allocator, not just the program's own code. Even libc, whenever calling through the official interface, will use the override. Similarly, by using "preloading", the user can inject additional libraries between the main executable and its shared object dependencies, allowing them to trace calls or substitute behavior.
Copy relocations move data residing in a shared object to the bss section of the main executable. The space there is reserved while linking the program (prone to resizing issues between library versions). The library has to be fixed-up or it will get split-brained from the rest of the process and therefore treats its own exported symbols as relocatable. The result is that the code segment of the non-PIC program does not need to be modified at load time, thus can be shared between processes. This potentially reduces the memory footprint. In both load ordering and copy relocations, libraries have to reimport their own exported symbols, because someone else may override their locations.
This
article is a critique of the performance cost of these features, which may provide you with clarifications.
Basically, you need to tell the compiler to assume that copy relocations and load order resolution will not be used to override the library's symbols. I am not personally aware of such an option, but note that even if you find one, such behavior may surprise programs not written specifically for your OS, so depending on how you plan to populate your userland, it may be a slight point of concern.
Edit: In a nutshell, the code cannot use local references as long as the compiler is trying to solve some other problem. It is trying to make possible late substitutions of global symbols.
For illustration purposes a small example. If you build this code for a library:
Code:
int x() { return 1; };
int y() { return x(); }
Code:
gcc --shared -mcmodel=large libx.c -o libx.so
you can check with
objdump -R libx.so that the library has relocation for its own x symbol. Now, if you build this code for the main executable:
Code:
int x() { return 2; }
int main() { return y(); }
Code:
gcc main.c -o main -L. -lx
you can see the override in action:
Code:
> LD_LIBRARY_PATH=. ./main; echo $?
2
On the other hand, if you build this code for the library:
Code:
int x() __attribute__ ((weak, alias ("x_")));
static int x_() { return 5; }
int y() { return x_(); }
you can check with objdump to see that the relocation is gone. The symbol x is still exported by the library, but the code only refers to the internal implementation behind the symbol. Actually, x is now a weak symbol with default value, but that is irrelevant. The exit code will will be obviously 1, but the important part is that the library is not relocated (for that symbol) anymore. As a side note, although as I said it is not relevant here, in Linux weak symbols are not treated specifically by the dynamic linker unless the LD_DYNAMIC_WEAK environment variable is defined.
Regards,