mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
Move arm_skip_solib_resolver from arm-linux-nat.c to arm-linux-tdep.c.
2000-04-10 Philip Blundell <philb@gnu.org> * arm-linux-nat.c (arm_skip_solib_resolver): Remove and move to arm-linux-tdep.c. * arm-linux-tdep.c (arm_skip_solib_resolver): New.
This commit is contained in:
parent
50da7a9c68
commit
f38e884d67
@ -1,3 +1,9 @@
|
|||||||
|
2000-04-10 Philip Blundell <philb@gnu.org>
|
||||||
|
|
||||||
|
* arm-linux-nat.c (arm_skip_solib_resolver): Remove and move to
|
||||||
|
arm-linux-tdep.c.
|
||||||
|
* arm-linux-tdep.c (arm_skip_solib_resolver): New.
|
||||||
|
|
||||||
2000-04-10 Fernando Nasser <fnasser@cygnus.com>
|
2000-04-10 Fernando Nasser <fnasser@cygnus.com>
|
||||||
|
|
||||||
From 2000-04-10 Rodney Brown <rdb@redhat.com>:
|
From 2000-04-10 Rodney Brown <rdb@redhat.com>:
|
||||||
|
@ -322,132 +322,6 @@ store_inferior_registers (int regno)
|
|||||||
store_fpregs ();
|
store_fpregs ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Dynamic Linking on ARM Linux
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Note: PLT = procedure linkage table
|
|
||||||
GOT = global offset table
|
|
||||||
|
|
||||||
As much as possible, ELF dynamic linking defers the resolution of
|
|
||||||
jump/call addresses until the last minute. The technique used is
|
|
||||||
inspired by the i386 ELF design, and is based on the following
|
|
||||||
constraints.
|
|
||||||
|
|
||||||
1) The calling technique should not force a change in the assembly
|
|
||||||
code produced for apps; it MAY cause changes in the way assembly
|
|
||||||
code is produced for position independent code (i.e. shared
|
|
||||||
libraries).
|
|
||||||
|
|
||||||
2) The technique must be such that all executable areas must not be
|
|
||||||
modified; and any modified areas must not be executed.
|
|
||||||
|
|
||||||
To do this, there are three steps involved in a typical jump:
|
|
||||||
|
|
||||||
1) in the code
|
|
||||||
2) through the PLT
|
|
||||||
3) using a pointer from the GOT
|
|
||||||
|
|
||||||
When the executable or library is first loaded, each GOT entry is
|
|
||||||
initialized to point to the code which implements dynamic name
|
|
||||||
resolution and code finding. This is normally a function in the
|
|
||||||
program interpreter (on ARM Linux this is usually ld-linux.so.2,
|
|
||||||
but it does not have to be). On the first invocation, the function
|
|
||||||
is located and the GOT entry is replaced with the real function
|
|
||||||
address. Subsequent calls go through steps 1, 2 and 3 and end up
|
|
||||||
calling the real code.
|
|
||||||
|
|
||||||
1) In the code:
|
|
||||||
|
|
||||||
b function_call
|
|
||||||
bl function_call
|
|
||||||
|
|
||||||
This is typical ARM code using the 26 bit relative branch or branch
|
|
||||||
and link instructions. The target of the instruction
|
|
||||||
(function_call is usually the address of the function to be called.
|
|
||||||
In position independent code, the target of the instruction is
|
|
||||||
actually an entry in the PLT when calling functions in a shared
|
|
||||||
library. Note that this call is identical to a normal function
|
|
||||||
call, only the target differs.
|
|
||||||
|
|
||||||
2) In the PLT:
|
|
||||||
|
|
||||||
The PLT is a synthetic area, created by the linker. It exists in
|
|
||||||
both executables and libraries. It is an array of stubs, one per
|
|
||||||
imported function call. It looks like this:
|
|
||||||
|
|
||||||
PLT[0]:
|
|
||||||
str lr, [sp, #-4]! @push the return address (lr)
|
|
||||||
ldr lr, [pc, #16] @load from 6 words ahead
|
|
||||||
add lr, pc, lr @form an address for GOT[0]
|
|
||||||
ldr pc, [lr, #8]! @jump to the contents of that addr
|
|
||||||
|
|
||||||
The return address (lr) is pushed on the stack and used for
|
|
||||||
calculations. The load on the second line loads the lr with
|
|
||||||
&GOT[3] - . - 20. The addition on the third leaves:
|
|
||||||
|
|
||||||
lr = (&GOT[3] - . - 20) + (. + 8)
|
|
||||||
lr = (&GOT[3] - 12)
|
|
||||||
lr = &GOT[0]
|
|
||||||
|
|
||||||
On the fourth line, the pc and lr are both updated, so that:
|
|
||||||
|
|
||||||
pc = GOT[2]
|
|
||||||
lr = &GOT[0] + 8
|
|
||||||
= &GOT[2]
|
|
||||||
|
|
||||||
NOTE: PLT[0] borrows an offset .word from PLT[1]. This is a little
|
|
||||||
"tight", but allows us to keep all the PLT entries the same size.
|
|
||||||
|
|
||||||
PLT[n+1]:
|
|
||||||
ldr ip, [pc, #4] @load offset from gotoff
|
|
||||||
add ip, pc, ip @add the offset to the pc
|
|
||||||
ldr pc, [ip] @jump to that address
|
|
||||||
gotoff: .word GOT[n+3] - .
|
|
||||||
|
|
||||||
The load on the first line, gets an offset from the fourth word of
|
|
||||||
the PLT entry. The add on the second line makes ip = &GOT[n+3],
|
|
||||||
which contains either a pointer to PLT[0] (the fixup trampoline) or
|
|
||||||
a pointer to the actual code.
|
|
||||||
|
|
||||||
3) In the GOT:
|
|
||||||
|
|
||||||
The GOT contains helper pointers for both code (PLT) fixups and
|
|
||||||
data fixups. The first 3 entries of the GOT are special. The next
|
|
||||||
M entries (where M is the number of entries in the PLT) belong to
|
|
||||||
the PLT fixups. The next D (all remaining) entries belong to
|
|
||||||
various data fixups. The actual size of the GOT is 3 + M + D.
|
|
||||||
|
|
||||||
The GOT is also a synthetic area, created by the linker. It exists
|
|
||||||
in both executables and libraries. When the GOT is first
|
|
||||||
initialized , all the GOT entries relating to PLT fixups are
|
|
||||||
pointing to code back at PLT[0].
|
|
||||||
|
|
||||||
The special entries in the GOT are:
|
|
||||||
|
|
||||||
GOT[0] = linked list pointer used by the dynamic loader
|
|
||||||
GOT[1] = pointer to the reloc table for this module
|
|
||||||
GOT[2] = pointer to the fixup/resolver code
|
|
||||||
|
|
||||||
The first invocation of function call comes through and uses the
|
|
||||||
fixup/resolver code. On the entry to the fixup/resolver code:
|
|
||||||
|
|
||||||
ip = &GOT[n+3]
|
|
||||||
lr = &GOT[2]
|
|
||||||
stack[0] = return address (lr) of the function call
|
|
||||||
[r0, r1, r2, r3] are still the arguments to the function call
|
|
||||||
|
|
||||||
This is enough information for the fixup/resolver code to work
|
|
||||||
with. Before the fixup/resolver code returns, it actually calls
|
|
||||||
the requested function and repairs &GOT[n+3]. */
|
|
||||||
|
|
||||||
CORE_ADDR
|
|
||||||
arm_skip_solib_resolver (CORE_ADDR pc)
|
|
||||||
{
|
|
||||||
/* FIXME */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
arm_linux_register_u_addr (int blockend, int regnum)
|
arm_linux_register_u_addr (int blockend, int regnum)
|
||||||
{
|
{
|
||||||
|
@ -221,6 +221,132 @@ arm_linux_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp,
|
|||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dynamic Linking on ARM Linux
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Note: PLT = procedure linkage table
|
||||||
|
GOT = global offset table
|
||||||
|
|
||||||
|
As much as possible, ELF dynamic linking defers the resolution of
|
||||||
|
jump/call addresses until the last minute. The technique used is
|
||||||
|
inspired by the i386 ELF design, and is based on the following
|
||||||
|
constraints.
|
||||||
|
|
||||||
|
1) The calling technique should not force a change in the assembly
|
||||||
|
code produced for apps; it MAY cause changes in the way assembly
|
||||||
|
code is produced for position independent code (i.e. shared
|
||||||
|
libraries).
|
||||||
|
|
||||||
|
2) The technique must be such that all executable areas must not be
|
||||||
|
modified; and any modified areas must not be executed.
|
||||||
|
|
||||||
|
To do this, there are three steps involved in a typical jump:
|
||||||
|
|
||||||
|
1) in the code
|
||||||
|
2) through the PLT
|
||||||
|
3) using a pointer from the GOT
|
||||||
|
|
||||||
|
When the executable or library is first loaded, each GOT entry is
|
||||||
|
initialized to point to the code which implements dynamic name
|
||||||
|
resolution and code finding. This is normally a function in the
|
||||||
|
program interpreter (on ARM Linux this is usually ld-linux.so.2,
|
||||||
|
but it does not have to be). On the first invocation, the function
|
||||||
|
is located and the GOT entry is replaced with the real function
|
||||||
|
address. Subsequent calls go through steps 1, 2 and 3 and end up
|
||||||
|
calling the real code.
|
||||||
|
|
||||||
|
1) In the code:
|
||||||
|
|
||||||
|
b function_call
|
||||||
|
bl function_call
|
||||||
|
|
||||||
|
This is typical ARM code using the 26 bit relative branch or branch
|
||||||
|
and link instructions. The target of the instruction
|
||||||
|
(function_call is usually the address of the function to be called.
|
||||||
|
In position independent code, the target of the instruction is
|
||||||
|
actually an entry in the PLT when calling functions in a shared
|
||||||
|
library. Note that this call is identical to a normal function
|
||||||
|
call, only the target differs.
|
||||||
|
|
||||||
|
2) In the PLT:
|
||||||
|
|
||||||
|
The PLT is a synthetic area, created by the linker. It exists in
|
||||||
|
both executables and libraries. It is an array of stubs, one per
|
||||||
|
imported function call. It looks like this:
|
||||||
|
|
||||||
|
PLT[0]:
|
||||||
|
str lr, [sp, #-4]! @push the return address (lr)
|
||||||
|
ldr lr, [pc, #16] @load from 6 words ahead
|
||||||
|
add lr, pc, lr @form an address for GOT[0]
|
||||||
|
ldr pc, [lr, #8]! @jump to the contents of that addr
|
||||||
|
|
||||||
|
The return address (lr) is pushed on the stack and used for
|
||||||
|
calculations. The load on the second line loads the lr with
|
||||||
|
&GOT[3] - . - 20. The addition on the third leaves:
|
||||||
|
|
||||||
|
lr = (&GOT[3] - . - 20) + (. + 8)
|
||||||
|
lr = (&GOT[3] - 12)
|
||||||
|
lr = &GOT[0]
|
||||||
|
|
||||||
|
On the fourth line, the pc and lr are both updated, so that:
|
||||||
|
|
||||||
|
pc = GOT[2]
|
||||||
|
lr = &GOT[0] + 8
|
||||||
|
= &GOT[2]
|
||||||
|
|
||||||
|
NOTE: PLT[0] borrows an offset .word from PLT[1]. This is a little
|
||||||
|
"tight", but allows us to keep all the PLT entries the same size.
|
||||||
|
|
||||||
|
PLT[n+1]:
|
||||||
|
ldr ip, [pc, #4] @load offset from gotoff
|
||||||
|
add ip, pc, ip @add the offset to the pc
|
||||||
|
ldr pc, [ip] @jump to that address
|
||||||
|
gotoff: .word GOT[n+3] - .
|
||||||
|
|
||||||
|
The load on the first line, gets an offset from the fourth word of
|
||||||
|
the PLT entry. The add on the second line makes ip = &GOT[n+3],
|
||||||
|
which contains either a pointer to PLT[0] (the fixup trampoline) or
|
||||||
|
a pointer to the actual code.
|
||||||
|
|
||||||
|
3) In the GOT:
|
||||||
|
|
||||||
|
The GOT contains helper pointers for both code (PLT) fixups and
|
||||||
|
data fixups. The first 3 entries of the GOT are special. The next
|
||||||
|
M entries (where M is the number of entries in the PLT) belong to
|
||||||
|
the PLT fixups. The next D (all remaining) entries belong to
|
||||||
|
various data fixups. The actual size of the GOT is 3 + M + D.
|
||||||
|
|
||||||
|
The GOT is also a synthetic area, created by the linker. It exists
|
||||||
|
in both executables and libraries. When the GOT is first
|
||||||
|
initialized , all the GOT entries relating to PLT fixups are
|
||||||
|
pointing to code back at PLT[0].
|
||||||
|
|
||||||
|
The special entries in the GOT are:
|
||||||
|
|
||||||
|
GOT[0] = linked list pointer used by the dynamic loader
|
||||||
|
GOT[1] = pointer to the reloc table for this module
|
||||||
|
GOT[2] = pointer to the fixup/resolver code
|
||||||
|
|
||||||
|
The first invocation of function call comes through and uses the
|
||||||
|
fixup/resolver code. On the entry to the fixup/resolver code:
|
||||||
|
|
||||||
|
ip = &GOT[n+3]
|
||||||
|
lr = &GOT[2]
|
||||||
|
stack[0] = return address (lr) of the function call
|
||||||
|
[r0, r1, r2, r3] are still the arguments to the function call
|
||||||
|
|
||||||
|
This is enough information for the fixup/resolver code to work
|
||||||
|
with. Before the fixup/resolver code returns, it actually calls
|
||||||
|
the requested function and repairs &GOT[n+3]. */
|
||||||
|
|
||||||
|
CORE_ADDR
|
||||||
|
arm_skip_solib_resolver (CORE_ADDR pc)
|
||||||
|
{
|
||||||
|
/* FIXME */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_initialize_arm_linux_tdep (void)
|
_initialize_arm_linux_tdep (void)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user