MIPS, ELF and partial binding

I have a large software project with a complex build process that works as follows:

  • Compile individual source files.
  • Partially link object files for each module with another .o using ld -r .
  • Hide private characters in each module using objcopy -G .
  • Partially bind the module objects together, again using ld -r .
  • Link the modules together with a common object.

Step 3 is needed to allow global module variables that are not exported to the rest of the project.

All this works great with ARM and IA32. Unfortunately, now I have to do something on mips (in particular, mipsel-linux-gnu for Android). And the general MIPS ABI object is much more complicated than on other platforms, and it does not work.

What happens is that in step 5 this error fails:

 CALL16 reloc at 0x1234 not against global symbol 

This is because the compiler generates CALL16 transitions for calling functions in another compilation unit, but CALL16 allows you to only call global characters --- and because of step 3 some of the characters that we are trying to call are no longer global.

At this moment, I see several possible options:

  • convince the linker to allow CALL16 transitions to regular PC-relative processing calls inside compilation in step 2.
  • same, but in step 4 or 5.
  • tell the compiler not to generate CALL16 moves for compilation function calls.
  • others.

Turning off step 3, I'm afraid, is not an option due to external requirements.

What I really would like to do is generate an absolute code, which is fixed when loading to the desired addresses; it is smaller, much faster and much simpler, and we do not need to share the library between processes. Unfortunately, it seems that Android dlopen() does not seem to support this.

I'm currently not in my depths. Anyone have any suggestions?

This is gcc 4.4.5 (from Emdebian), binutils 2.20.1. The target BFD is elf32-tradlittlemips. The host system is Linux and I use cross-compilation for Android.

Adding

I also get warnings similar to this from step 4.

 $MODULE.o: Can't find matching LO16 reloc against `$SYMBOLNAME' for R_MIPS_GOT16 at 0x18 in section `.text.$SYMBOLNAME' 

Looking at the parsing of the input in step 4, I see that the compiler generated the code as follows:

 50: 8f9e0000 lw s8,0(gp) 50: R_MIPS_GOT16 $SYMBOLNAME 54: 8fd9001c lw t9,28(s8) 58: 0320f809 jalr t9 5c: 00a02021 move a0,a1 

Is GOT16 not fixing the top half of the address, and should LO16 follow for the bottom half? But the code looks like it is trying to touch the GOT. It puzzles me. I do not know if this is due to my earlier problem or is it another problem or is it not a problem at all ...

Update

Apparently, MIPS just doesn't support hidden global characters!

We went around it, distorting the names of the characters that should be hidden so that no one could say what it is. This pretty much pushes external requirements, but I sold them management, indicating that this is the only way to get a shippable product.

This is absolutely horrible (and includes some very disgusting makefile work), so I would prefer a better solution if anyone has ...

+4
source share
2 answers

I am not sure about the specific GOT issues you have. There are many errors and problems with GOT, LO16 / HI16 in binutils. I think most of them have been fixed in the version you are using, unless you are targeting MIPS16 (which you don't seem to be doing). LO16 is really only needed there, behind MIPS16 you pull the full 26-bit offset from the GOT, since you have 32-bit registers. LO16 is not required, but it is still formally required by some ABI / APIs, but it was underestimated as a warning (you can try to remove -Werror at this point if you use it). I understand only the very basics of this part, the rest of your situation I had some recommendations, although if not the answer (it's hard to make sure, given the complexity of your installation).

In MIPS (and in most of the collections I’m familiar with), you have three main levels of visibility: local, global, and weak. In addition, you have common to common objects. GNU, of course, likes to complicate things and add more. gas provides sheltered, hidden and internal (it is minimally difficult to maintain all extensions). With all this, the steps that your setting in manual mode with visibility seem unnecessary.

If you can remove the intermediate globality of the variables, it must delete, you must make them nonsmooth, which can only simplify any GOT problems that you will encounter later.

Common problems are a bit confusing. I'm not sure what you mean by hidden global symbols, this is a bit contrary (of course, portability and specific projects give crazy problems and limitations). It seems you want the symbols of the transverse assembly to be displayed at one stage, but not at a later stage. Without using the GNU extensions (which is best avoided in my book), you might want to replace the globals in steps 1-2 with comm and / or weakglobals. You can always use the use of a preprocessor to avoid having several subunits at the stage even (ugly but portable code at this level).

You really have setup 1) submodules 2) submodules → modules 3-5) modules → shared library. Simplification of this cannot hurt. You can always embed a C-level interface in 2) or 3-5) just to find which GCC build will be the product for your architectures and use this as a basis for breaking visibility into clean interfaces.

I wish that I could give you an individual solution, but this is quite impossible without your full-fledged project. I can assure you that while there are problems in the MIPS location (especially in the tools), the visibility parameters (especially if you use gas, libbfd and gcc) are the same.

+1
source

your binutils is too old. some changes in 2.23 may solve your problem, for example, "hide characters without PLT or GOT links".

0
source

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


All Articles