5

I have a bunch of object files that have been compiled without the -fPIC option. So the calls to the functions do not use @PLT. (source code is C and is compiled with clang).

I want to link these object files into a shared library that I can load at runtime using dlopen. I need to do this because I have to do a lot of setup before the actual .so is loaded.

But every time I try to link with the -shared option, I get the error -

relocation R_X86_64_PC32 against symbol splay_tree_lookup can not be used when making a shared object; recompile with -fPIC

I have no issues recompiling from source. But I don't want to use -fPIC. This is part of a research project where we are working on a custom compiler. PIC wouldn't work for the type of guarantees we are trying to provide in the compiler.

Is there some flag I can use with ld so that it generate load time relocating libraries. In fact I am okay with no relocations. I can provide a base address for the library and dlopen can fail if the virtual address is not available.

The command I am using for compiling my c files are equivalent to -

clang -m64 -c foo.c

and for linking I am using

clang -m64 -shared *.o -o foo.so

I say equivalent because it is a custom compiler (forked off clang) and has some extra steps. But it is equivalent.

jxh
  • 69,070
  • 8
  • 110
  • 193
Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • You might be able to do it in ASM with `.orig` directive (I think that's the one). Also see [Linking symbols to fixed addresses on Linux](https://stackoverflow.com/q/495262/608639), [Is there a way to load a Linux shared library into a specific memory location?](https://stackoverflow.com/q/25919859/608639), [How to create static linked shared libraries](https://stackoverflow.com/q/25172834/608639), etc. Also see [relocatable code and object files and shared libraries](https://gcc.gnu.org/ml/gcc-help/2008-10/msg00183.html) (see Ian lance Taylor's reply). – jww Feb 21 '18 at 10:31
  • Can you share how splay_tree_lookup is called/referenced. Which library provides the splut_tree_lookup - how was it compiled ? – dash-o Oct 23 '19 at 15:23
  • 2
    This is a duplicate of https://stackoverflow.com/questions/7865059/why-does-gcc-force-pic-for-x64-shared-libs Note [the answer there](https://stackoverflow.com/a/7865081/4756299): PIC is effectively *required* on 64-bit shared objects on x86_64 systems. – Andrew Henle Oct 23 '19 at 16:07
  • https://stackoverflow.com/a/12139145/1162141 has a good example. You could set up a struct with function pointers and then use the function pointers through a macro. – technosaurus Oct 24 '19 at 00:11
  • @AndrewHenle I think a good "this isn't possible because..." answer would suffice for a bounty. I confess, I failed to find the related question you linked when I was investigating this myself. – James_pic Oct 24 '19 at 13:42
  • You can't build a shared library on x86_64 without PIC. It won't work. – S.S. Anne Oct 27 '19 at 15:16

2 Answers2

2

It is not possible to dynamically load your existing non PIC objects with the expectation of it working without problems.

If you cannot recompile the original code to create a proper shared library that supports PIC, then I suggest you create a service executable that links to a static library composed of those objects. The service executable can then provide IPC/RPC/REST API/shared memory/whatever to allow your object code to be used by your program.

Then, you can author a shared library which is compiled with PIC that provides wrapper APIs that launches and communicates with the service executable to perform the actual work.

On further thought, this wrapper API library may as well be static. The dynamic aspect of it is performed by launching the service executable.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • *with the expectation of it working without problems* -- if I understand correctly, these problems would be at load time. But we had our custom loader that didn't care about relocations. It would always load at a fixed address. I think it is reasonable in that case to have a .so not compiled with `-fPIC`. Also, as mentioned in another comment, I had no issues with recompiling. We had access to the source. But we were building a custom compiler and `-fPIC` just wouldn't be compatible with the kind of guarantees we were trying to provide in the compiler. – Ajay Brahmakshatriya Oct 25 '19 at 18:23
  • 1
    `-fPIC` would allow it to work. Isn't that the most important guarantee? Linux may decide to swap out code pages for `.so` but not place them in the backing store. When Linux "swaps" those code pages back in, it is pulling from the `.so` file directly. This is why I think there is low chances of it working, since when the pages get swapped back in, since it is not `-fPIC` compiled, its state may not be correct, since it won't be "initialized" by your dynamic loader on the swap in. – jxh Oct 25 '19 at 18:47
-1

Recompiling the library's object files with the -fpic -shared options would be the best option, if this is possible!


man ld says:

-i Perform an incremental link (same as option -r).

-r
--relocatable

Generate relocatable output---i.e., generate an output file that can in turn serve as input to ld. This is often called partial linking. As a side effect, in environments that support standard Unix magic numbers, this option also sets the output file’s magic number to "OMAGIC". If this option is not specified, an absolute file is produced. When linking C++ programs, this option will not resolve references to constructors; to do that, use -Ur.

When an input file does not have the same format as the output file, partial linking is only supported if that input file does not contain any relocations. Different output formats can have further restrictions; for example some "a.out"-based formats do not support partial linking with input files in other formats at all.

I believe you can partially link your library object files into a relocatable (PIC) library, then link that library with your source code object file to make a shared library.

ld -r -o libfoo.so *.o
cp libfoo.so /foodir/libfoo.so
cd foodir
clang -m32 -fpic -c foo.c
clang -m32 -fpic -shared *.o -o foo.so

Regarding library base address:

(Again from man ld)

--section-start=sectionname=org

Locate a section in the output file at the absolute address given by org. You may use this option as many times as necessary to locate multiple sections in the command line. org must be a single hexadecimal integer; for compatibility with other linkers, you may omit the leading 0x usually associated with hexadecimal values. Note: there should be no white space between sectionname, the equals sign ("="), and org.

You could perhaps move your library's .text section?

--image-base value

Use value as the base address of your program or dll. This is the lowest memory location that will be used when your program or dll is loaded. To reduce the need to relocate and improve performance of your dlls, each should have a unique base address and not overlap any other dlls. The default is 0x400000 for executables, and 0x10000000 for dlls. [This option is specific to the i386 PE targeted port of the linker]

Community
  • 1
  • 1
LegendofPedro
  • 1,393
  • 2
  • 11
  • 23
  • 3
    Recompiling the object files with `-fpic` is the **only** option. PIC is required for x86_64 shared objects. They won't work otherwise. – Andrew Henle Oct 23 '19 at 16:08
  • 1
    So it might still be possible with the `-m32` flag? – LegendofPedro Oct 23 '19 at 17:39
  • 1
    *So it might still be possible with the `-m32` flag?* Indeed. PIC is not required for a 32-bit shared object on x86 systems, but I'm not sure if recent, commonly-used toolchains can build a 32-bit shared object. Shouldn't be too hard to test, but I can't right now. [Address space layout randomization (ASLR)](https://en.wikipedia.org/wiki/Address_space_layout_randomization) might come into play, too. – Andrew Henle Oct 23 '19 at 18:14
  • Unfortunately, I can't test it either, but I recently went through linking hell trying to build `valgrind4win` and read a whole bunch about `ld`. – LegendofPedro Oct 23 '19 at 18:48
  • @AndrewHenle I understand that general loaders would require the object files be compiled with `-fPIC` when linking into a `.so`. But if you have a custom loader that wants to load the `.so` at a fixed address, `-fPIC` is not necessary. The question is can the GNU linker be used to create no relocatable so files? – Ajay Brahmakshatriya Oct 23 '19 at 20:06
  • You say "you can partially link your library object files into a relocatable (PIC) library", but the subtlety is that relocatable =/=> PIC. The code is already relocatable (it's got enough info for a linker to relink it at a new location), but isn't PIC, and can't be made PIC. I think it is possible with the `-m32` flag, but that would also be recompiling, and if you were going to recompile, you'd just use `-fpic`. I guess I was hoping someone knew "this one weird trick" that would persuade the dynamic linker to always load code into the bottom 2GB, so relocations could be done safely. – James_pic Oct 24 '19 at 14:04
  • @James_pic I have no issues recompiling from source. But I don't want to use `-fpic`. This was part of a research project where we were working on custom compiler. PIC wouldn't work for the type of guarantees we were trying to provide in the compiler. Also, we wanted to make it work for 64 bit binaries. We also had our custom loader so relocations weren't an issue. I guess the question should have been can ld be made to work for non-standard linkers. – Ajay Brahmakshatriya Oct 25 '19 at 18:20
  • @AjayBrahmakshatriya makes sense. I assumed you'd asked the question for the same reason I was here (I'd been given a binary blob and told "integrate that"), but it sounds like you've got a subtly different set of problems. – James_pic Oct 26 '19 at 13:41