From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ian Lance Taylor To: hjl@lucon.org Cc: gas2@cygnus.com, libc-hacker@cygnus.com Subject: Re: Has anyone looked at ELF 4.1? Date: Sun, 16 Aug 1998 20:01:00 -0000 Message-id: <199808170258.WAA23765@subrogation.cygnus.com> References: X-SW-Source: 1998/msg00208.html From: hjl@lucon.org (H.J. Lu) Date: Sun, 16 Aug 1998 18:58:10 -0700 (PDT) # ldd /usr/bin/groff libstdc++.so.2.8 => /usr/lib/libstdc++.so.2.8 (0x40007000) libm.so.6 => /lib/libm.so.6 (0x4004c000) libc.so.6 => /lib/libc.so.6 (0x40065000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000) The problem is /usr/lib/libstdc++.so.2.8 was compiled again glibc 2.0.x. When running on a glibc 2.1 machine, /lib/libc.so.6 is glibc 2.1, which supports the same C ABI in glibc 2.0 using the symbol versioning. But glibc 2.1 has a different C++ ABI. Please keep in mind that libio in glibc has 2 ABIs, one for C and the other for C++. If the ABI changed between glibc 2.0.x and glibc 2.1, then either the name of the library has to change or we need to use symbol versioning. To put it another way, why are those capabilities not adequate to fix this problem? I want to make sure that you are fixing a real problem here, not a problem that has temporarily arisen because glibc happened to not use symbol versioning for the C++ interface (if that is indeed what happened). You are proposing a new capability in the toolchain. We should only add it if we need it. > If groff once worked, and then broke, then it sounds as though > somebody must have made an incompatible change to the libstdc++ > library interface. Anybody who makes an incompatible change must > change the library version number. Using the new ELF specs won't save > us from that sort of failure; it is equivalent to failing to increase > the version number in the ELF specs. The problem is the incompatible C++ ABIs in libio between glibc 2.0 and glibc 2.1. I don't see how this contradicts the paragraph you quoted. I said that anybody who makes an incompatible change must change the library version number. You have to explain why neither the library version number nor the symbol versions changed. > What do the new ELF specs give us that we don't get from symbol > versioning and changing library names? We didn't change the library name of libc since the C ABI is ok. The problem is the C++ ABI in libc. It is very unique to Linux since we use the same code in libio for both libc and libstdc++. A change in the C++ ABI is a change in the library ABI. We use symbol versioning to give us the ability to change a part of an ABI. Why does that not work in this case? > 1. Add switchs to ld to set EI_OSABI and EI_ABIVERSION. > 2. For Linux, set EI_ABIVERSION with C ABI and C++ ABI. > > EI_ABIVERSION = (0xf & C_ABI) | (0xf0 & C++_ABI) > > What precisely do you mean here by C_ABI and C++_ABI? You presumably > do not mean the version of the library, because there is no need to > record that. No. I mean the ABI version, like #ifdef glibc 2.0 #define CXX_ABI 0 #define C_ABI 0 #elif defined glibc 2.1 #define CXX_ABI 1 #define C_ABI 0 #endif That is not an explanation. What do you mean by C_ABI? If we change the name of the library, does the C_ABI change? Why or why not? > Four bits only gives you sixteen versions, which is not a lot. I think 16 is more than enough. We may want 3 bits for C++ and 5 bits for C. How is 16 more than enough? What kind of time frame are you thinking of? You're saying that the C++ ABI needs to change from glibc 2.0 to 2.1. Won't it change just about every time a new library is released? If not, why not? > 3. ld sets EI_OSABI depending on target if it is not set at the command > line. > > How does ld determine EI_OSABI? Linker script? We already pass "-dynamic-linker /lib/ld-linux.so.2" to ld for Linux. We can pass another one if necessary. Making the compiler aware of the dynamic linker version number in this way is a bogus hack, since it makes the compiler unnecessarily dependent on the system version number. You really ought to be able to use the same compiler on most Linux versions. After all, the code generation doesn't change, and all the system dependencies are reflected in the header files. Introducing another system dependency into the compiler is a step backward, not forward. > 4. ld sets EI_ABIVERSION depending on EI_ABIVERSION in the shared > library used to build an ELF binary if it is not set at the command > line. > > This seems pointless. The library version number is already recorded > in the DT_SONAME entry. If it isn't, then where is it, and how does I am talking about C/C++ ABI version. soname is mainly for C programs which don't care about the C++ ABI. No. DT_SONAME is for anybody who uses a library, and it applies to all interfaces of the library. It is a bug to think that DT_SONAME only applies to part of a library's interface. > ld determine EI_ABIVERSION? When we build a dynamic ELF object on Linux, we should always pass -lc to it. ld can get EI_ABIVERSION from libc.so. I think it's bogus to make ld treat libc specially. It should be logically possible to build a dynamic executable which does not depend on libc. Also, one of the more logical uses for EI_ABIVERSION would be for statically linked binaries, since they don't get to adapt to the system using dynamic linking. > 5. The dynamic linker will check both EI_OSABI and EI_ABIVERSION when > choosing which shared library to load. With that, we can have both 2 > libc.so.6 with different EI_ABIVERSIONs in different directories. > > Why would we want such a thing? > > How precisely will this approach help with groff? > > I think we have a problem with using multiple libraries which are > linked against different versions of libc. However, I don't see how > EI_OSABI and EI_ABIVERSION can help with that. > > We already have two library versioning schemes: DT_SONAME, and symbol > versioning. Why do we need a third? What deficiency in the existing > schemes does it address? We may want to load a different libc.so.6 depending on the C++/C ABI version. For groff, on glibc 2.1, we want # ldd /usr/bin/groff libstdc++.so.2.8 => /usr/lib/libstdc++.so.2.8 (0x40007000) libm.so.6 => /usr/glibc-2.0/lib/libm.so.6 (0x4004c000) libc.so.6 => /usr/glibc-2.0/libc.so.6 (0x40065000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000) I don't understand why this is an answer to my question. Ian