Mixing PIC and Non-PIC Objects in a Shared Library

This question is related to this and its answer.

I just discovered some ugliness in the assembly I'm working on. The situation looks something like this: (in gmake format); Note that this applies to the 32-bit memory model on sparc and x86 hardware:

OBJ_SET1 := some objects OBJ_SET2 := some objects # note: OBJ_SET2 doesn't get this flag ${OBJ_SET1} : CCFLAGS += -PIC ${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<} obj1.o : ${OBJ_SET1} obj2.o : ${OBJ_SET2} sharedlib.so : obj1.o obj2.o obj1.o obj2.o sharedlib.so : ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^} 

Obviously, it can work to mix objects compiled with and without PIC in a common object (this has been used for many years). I don’t know enough about PIC to find out if this is a good idea / smart, and I assume that in this case it is not needed, but rather happens because someone did not care about finding the right way to do this, on new material for assembly.

My question is:

  • It is safe
  • This is a good idea.
  • What potential problems might result from
  • If I switch everything to PIC, are there any non-obvious errors that I might want.
+6
source share
1 answer

I forgot, I even wrote this question.

Some explanations in the first place:

  • Non-PIC code can be loaded by the OS at any position in memory in [most] modern OSs. After everything is loaded, it goes through a phase that captures the text segment (where the executable ends), so it correctly addresses global variables; To remove this, the text segment must be writable.
  • PIC executable data can be loaded once by the OS and distributed among several users / processes. However, for the OS, this text segment should be read-only, which means no fixes. The code is compiled to use the global offset table (GOT), so it can address global variables relative to the GOT, reducing the need for correction.
  • If a shared facility is built without PIC, although it is highly recommended, it does not seem to be strictly necessary; if the OS needs to fix the text segment, then it is forced to load it into memory, which is marked as read-write ..., which prevents the sharing of processes / users.
  • If the executable binary is built / s / PIC, I don’t know what will go wrong under the hood, but I witnessed that some tools became unstable (mysterious crashes, etc.).

Answers:

  • Mixing PIC / non-PIC or using PIC in executable files can make prediction and tracking instabilities difficult. Why I don’t have a technical explanation.
    • ... include segfaults, bus errors, stack corruption, and possibly more.
  • Non-PICs in shared objects are unlikely to cause serious problems, although this can lead to more RAM if the library is used many times for processes and / or users.

update (4/17)

Since then, I have discovered the cause of some of the accidents that I saw earlier. To illustrate:

 /*header.h*/ #include <map> typedef std::map<std::string,std::string> StringMap; StringMap asdf; /*file1.cc*/ #include "header.h" /*file2.cc*/ #include "header.h" int main( int argc, char** argv ) { for( int ii = 0; ii < argc; ++ii ) { asdf[argv[ii]] = argv[ii]; } return 0; } 

... then:

 $ g++ file1.cc -shared -PIC -o libblah1.so $ g++ file1.cc -shared -PIC -o libblah2.so $ g++ file1.cc -shared -PIC -o libblah3.so $ g++ file1.cc -shared -PIC -o libblah4.so $ g++ file1.cc -shared -PIC -o libblah5.so $ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa # ^^^^^^^^^ # This is the evil that made it possible $ args=(this is the song that never ends); $ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done) 

This specific example may not end in failure, but basically this is the situation that existed in this group code. If he commits , he will most likely end up in the destructor, usually a double mistake.

Over the past few years, they added -zmuldefs to their assembly to get rid of multi-valued character errors. The compiler emits code to run constructors / destructors on global objects. -zmuldefs makes them live in the same place in memory, but it still runs the constructors / destructors once for exe and each library that includes the offending header - hence dual access.

+4
source

Source: https://habr.com/ru/post/902778/


All Articles