This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: What is needed to support uclinux shared libraries on MMU-lessARM?


John Lee wrote:
Bernardo Innocenti, thanks again!


I don't know for sure since I've not used the ARM much
and never with uClinux.  I think it's better if you
subscribe to the uClinux mailing list (which I've now
added in Cc).

I have subscribed to the uClinux-dev mailing list, but nobody concerns it.

I don't quite understand. Did you mean that nobody cares about adding shared library support for MMU-less ARMs? I've seen this question asked several times on the uClinux mailing-list.

If you meant that nobody knows about it, well all the
people who made the current ARM and m68k toolchains
for uClinux are active posters in uclinux-dev and
they helped me a lot with my m68k work.


It would be more efficient to load A5 once in main() and
leave it there, but then you'd need to explicitly tell
the compiler to reload A5 in a few special functions,
defating the intent of this technique (i.e.: making the
library thing as transparent as possible for maximum
portability).

I don't understand it yet.
For example:
The main() function of an application(id = 0) would call function
TestA() in libA(a shared library, id = 2), function TestA() would call function TestB() in libB(another shared library, id = 3), and
function function TestB() would call a function in other shared
library, then after compiled:
In function main(), there are instructions as below:
..
move (a5 - 0*4),a5
call TestA()

Wait a moment. There's another detail I didn't tell you. The m68k backend does a trick with m68k_library_id_string to avoid some duplicate code.

There are *two* ways to compile a program:

-mid-shared-library

and

-mid-shared-library -mshared-library-id=N

The first one is for programs.  It generates this
code:

move.l %a5 + _current_shared_library_a5_offset_,%a5

The second one is used in libaries and it does
what you said:

move.l 2 * -4 - 4 + %a5,%a5


in function TestA() in libA, there are instructions as below:
..
move (a5 - 2*4),a5
call TestB()
..
and in function TestB() in libB, there are instructions as below:
..
move (a5 - 3*4),a5
..

As you see, the value of a5 is changed ceaselessly.

It looks odd, but it doesn't actually change the value of a5 when you libA keeps calling its own functions.

See below for the explanation given by Paul Dale on
the GCC mailing-list several months ago when I was
submitting patches for the m68k back-end.


So I have the following questions:
1. In function main() of the application, what is the first value of a5? Who load the initialization of a5?

Look for get_pic_a5() in linux-2.4.x/arch/m68knommu/platform/5307/signal.c. For 2.6, I dunno where they've hidden it ;-)


For libraries, there's also an additional trick in the startup code:

/* We've got to provide an entry point that doesn't stuff around with a5 like
* C routines tend to do.  We must also setup a5 from d5 which won't point to
* this libraries data segment but from which it can be obtained.
*/
asm(    ".globl lib_main\n\t"
       ".type lib_main,@function\n"
       "lib_main:\n\t"
       "move.l %d5, %a5\n\t"
       "bra.w main\n"
       ".L__end_lib_main__:\n\t"
       ".size lib_main,.L__end_lib_main__-libmain"
);

This is in uclinux/lib/libc/main.c, but uClibc also links
this file when it's built as a shared library (see uClibc's
top-level Makefile).


2. When the application running in TestB(), the value of a5
will equal to ((a5 - 0*4) - 2*4) - 3*4. I think it must be wrong somewhere in my comprehension.
But where is wrong?

It's because programs are compiled without -mshared-library-id=N so they use the first method.


3. After the application returning from TestA() to the function
main(),the value of a5 in function main(() will be changed to (a5 - 0*4) - 2*4. Is it right?

No, because the compiler marks a5 as a used register and will save it on the stack in the prologue *before* changing its value. Before returning from TestA, the original value of %a5 will be restored.



-------- Original Message --------
To: Bernardo Innocenti <bernie@develer.com>
Cc: Richard Henderson <rth@redhat.com>, gcc-patches@gcc.gnu.org,   Pauli <pauli@moreton.com.au>
Subject: Re: [m68k] Add uClinux-specific code generation options
Date: Fri, 12 Sep 2003 07:45:48 +1000
From: Pauli <pauli@moreton.com.au>

Bernardo wrote:

Richard Henderson wrote:
> On Wed, Sep 03, 2003 at 11:41:07PM +0200, Bernardo Innocenti wrote:
> >>+#define LEA(sym,reg) movel a5@(_current_shared_library_a5_offset_), > > I assume _current_shared_library_a5_offset_ is some sort of magic
> assembler/linker symbol?

Yes. It's declared in a startup file provided by uClibc, and it's
initialized in a function called before main().

Actually this is provided by a linker symbol :-)


I'll try to give a brief explanation of shared libraries in our no MMU world in case anybody really cares...

Each program and library that it uses is allocated its own data segment. At the start of each of these we maintain a (small) table of pointers to all of the various data segments. This means that the function prologue code can do:

move.l a5@(my_offset), a5

to guarantee that a5 now points to its data segment (& GOT) regardless of which module it came from. Hence that module can access its data segment and GOT.

We process each of the various GOTs at load time to relocate everything appropriately (including references between different modules).



--
 // Bernardo Innocenti - Develer S.r.l., R&D dept.
\X/  http://www.develer.com/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]