This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
Re: patch for ARM GNU/Linux gdbserver
- To: Philip Blundell <Philip dot Blundell at pobox dot com>
- Subject: Re: patch for ARM GNU/Linux gdbserver
- From: Scott Bambrough <scottb at netwinder dot org>
- Date: Mon, 10 Apr 2000 16:46:59 -0400
- CC: gdb-patches at sourceware dot cygnus dot com
- Organization: Rebel.com
- References: <E12e3tL-0001VY-00@kings-cross.london.uk.eu.org>
FYI,
I've split this patch into two parts. This is the first part which I have
committed on both the branch and the mainline.
Scott
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.
Philip Blundell wrote:
>
> This patch seems to be needed for gdbserver to work on Linux/ARM.
>
> p.
>
> 2000-04-08 Philip Blundell <philb@gnu.org>
>
> * arm-linux-nat.c (arm_skip_solib_resolver): Move to ...
> * arm-linux-tdep.c (arm_skip_solib_resolver): ... here.
>
> * gdbserver/low-linux.c: Add support for ARM GNU/Linux.
> * config/arm/tm-linux.h (ARM_GNULINUX_TARGET): Define.
> * configure.tgt [arm*-*-linux*]: Add gdbserver to $configdirs.
>
> Index: arm-linux-nat.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
> retrieving revision 1.4
> diff -u -p -u -r1.4 arm-linux-nat.c
> --- arm-linux-nat.c 2000/04/05 15:38:05 1.4
> +++ arm-linux-nat.c 2000/04/08 22:36:59
> @@ -322,132 +322,6 @@ store_inferior_registers (int regno)
> 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
> arm_linux_register_u_addr (int blockend, int regnum)
> {
> Index: arm-linux-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/arm-linux-tdep.c,v
> retrieving revision 1.2
> diff -u -p -u -r1.2 arm-linux-tdep.c
> --- arm-linux-tdep.c 2000/04/05 17:24:08 1.2
> +++ arm-linux-tdep.c 2000/04/08 22:36:59
> @@ -76,6 +76,132 @@ arm_linux_extract_return_value (struct t
> memcpy (valbuf, ®buf[REGISTER_BYTE (regnum)], TYPE_LENGTH (type));
> }
>
> +/*
> + 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
> _initialize_arm_linux_tdep (void)
> {
> Index: configure.tgt
> ===================================================================
> RCS file: /cvs/src/src/gdb/configure.tgt,v
> retrieving revision 1.5
> diff -u -p -u -r1.5 configure.tgt
> --- configure.tgt 2000/03/21 05:26:31 1.5
> +++ configure.tgt 2000/04/08 22:37:00
> @@ -52,7 +52,8 @@ alpha*-*-linux*) gdb_target=alpha-linux
> arc-*-*) gdb_target=arc ;;
>
> arm*-wince-pe) gdb_target=wince ;;
> -arm*-*-linux*) gdb_target=linux ;;
> +arm*-*-linux*) gdb_target=linux
> + configdirs="${configdirs} gdbserver" ;;
> arm*-*-* | thumb*-*-* | strongarm*-*-*)
> gdb_target=embed
> configdirs="$configdirs rdi-share"
> Index: config/arm/tm-linux.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/config/arm/tm-linux.h,v
> retrieving revision 1.3
> diff -u -p -u -r1.3 tm-linux.h
> --- config/arm/tm-linux.h 2000/02/28 20:51:08 1.3
> +++ config/arm/tm-linux.h 2000/04/08 22:37:11
> @@ -26,6 +26,8 @@
>
> #include "tm-linux.h"
>
> +#define ARM_GNULINUX_TARGET
> +
> /* Target byte order on ARM Linux is not selectable. */
> #undef TARGET_BYTE_ORDER_SELECTABLE_P
> #define TARGET_BYTE_ORDER_SELECTABLE_P 0
> Index: gdbserver/low-linux.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/low-linux.c,v
> retrieving revision 1.2
> diff -u -p -u -r1.2 low-linux.c
> --- gdbserver/low-linux.c 2000/03/21 05:23:05 1.2
> +++ gdbserver/low-linux.c 2000/04/08 22:37:15
> @@ -276,6 +276,20 @@ m68k_linux_register_u_addr (blockend, re
> {
> return (blockend + 4 * regmap[regnum]);
> }
> +#elif defined(ARM_GNULINUX_TARGET)
> +static void
> +initialize_arch ()
> +{
> + return;
> +}
> +
> +/* From arm-linux-nat.c */
> +int
> +arm_linux_register_u_addr (int blockend, int regnum)
> +{
> + return blockend + REGISTER_BYTE (regnum);
> +}
> +
> #elif defined(IA64_GNULINUX_TARGET)
> #undef NUM_FREGS
> #define NUM_FREGS 0
--
Scott Bambrough - Software Engineer
REBEL.COM http://www.rebel.com
NetWinder http://www.netwinder.org
philb1.patch