2003-06-05 14:32:49

by Richard B. Johnson

[permalink] [raw]
Subject: Shared Library starter, ld.so


I know this is not a Kernel problem but... it is an
embedded system problem using Linux with a very
minimal (homemade) 'C' runtime library.

The dynamic linker, provided with RedHat 9 no longer
compiles with the de facto standard of having register
EDX point to function to be called before exit.

This is (was) the relevent rule:

#
# This is the entry point, usually the first thing in the text
# segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that upon
# entry most registers' values are unspecified, except for:
#
# %edx Contains a function pointer to be registered with `atexit'.
# This is how the dynamic linker arranges to have DT_FINI
# functions called for shared libraries that have been loaded
# before this code runs.
#
# %esp The stack contains the arguments and environment:
# 0(%esp) argc
# 4(%esp) argv[0]
# ...
# (4*argc)(%esp) NULL
# (4*(argc+1))(%esp) envp[0]
# ...
# NULL

Now the register contains junk, so if it was used as a function-
pointer, the code will seg-fault.

How does code 'know' not to call this function? If this is
no longer used, then EDX must be set to zero to let the start-up
code know not to call it.

I tried to find the source-code for ld.so (ld-linux.so.2) used with
this version and was not able to find it anywhere.


Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips).
Why is the government concerned about the lunatic fringe? Think about it.


2003-06-06 09:59:43

by Richard Henderson

[permalink] [raw]
Subject: Re: Shared Library starter, ld.so

On Thu, Jun 05, 2003 at 10:46:18AM -0400, Richard B. Johnson wrote:
> The dynamic linker, provided with RedHat 9 no longer
> compiles with the de facto standard of having register
> EDX point to function to be called before exit.

You're wrong. Indeed, the rh9 crt1.o still expects the value:


8: 50 push %eax
9: 54 push %esp
a: 52 push %edx <<==== HERE
b: 68 00 00 00 00 push $0x0
c: R_386_32 __libc_csu_fini
10: 68 00 00 00 00 push $0x0
11: R_386_32 __libc_csu_init
15: 51 push %ecx
16: 56 push %esi
17: 68 00 00 00 00 push $0x0
18: R_386_32 main
1c: e8 fc ff ff ff call 1d <_start+0x1d>
1d: R_386_PC32 __libc_start_main

and ld.so provides the value here:

# Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
leal _dl_fini@GOTOFF(%ebx), %edx\n\



r~

2003-06-06 11:19:52

by Richard B. Johnson

[permalink] [raw]
Subject: Re: Shared Library starter, ld.so

On Fri, 6 Jun 2003, Richard Henderson wrote:

> On Thu, Jun 05, 2003 at 10:46:18AM -0400, Richard B. Johnson wrote:
> > The dynamic linker, provided with RedHat 9 no longer
> > compiles with the de facto standard of having register
> > EDX point to function to be called before exit.
>
> You're wrong. Indeed, the rh9 crt1.o still expects the value:
>
>
> 8: 50 push %eax
> 9: 54 push %esp
> a: 52 push %edx <<==== HERE
> b: 68 00 00 00 00 push $0x0
> c: R_386_32 __libc_csu_fini
> 10: 68 00 00 00 00 push $0x0
> 11: R_386_32 __libc_csu_init
> 15: 51 push %ecx
> 16: 56 push %esi
> 17: 68 00 00 00 00 push $0x0
> 18: R_386_32 main
> 1c: e8 fc ff ff ff call 1d <_start+0x1d>
> 1d: R_386_PC32 __libc_start_main
>
> and ld.so provides the value here:
>
> # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
> leal _dl_fini@GOTOFF(%ebx), %edx\n\
>

I am NOT wrong. I have crt startup code and if you actually CALL
the value in %edx, you __will__ segfault. So do a bit of research
before you claim that I'm wrong. Newer versions of the 'C' runtime
library simply fail to call that pointer in atexit(), before exit()
is called.

These things are so easily checked. Just assemble and link this code
against your favorite shared library.

#
# This is the entry point, usually the first thing in the text
# segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that upon
# entry most registers' values are unspecified, except for:
#
# %edx Contains a function pointer to be registered with `atexit'.
# This is how the dynamic linker arranges to have DT_FINI
# functions called for shared libraries that have been loaded
# before this code runs.
#
# %esp The stack contains the arguments and environment:
# 0(%esp) argc
# 4(%esp) argv[0]
# ...
# (4*argc)(%esp) NULL
# (4*(argc+1))(%esp) envp[0]
# ...
# NULL
#


.section .text
.global _start
.type _start,@function
_start: call *%edx
pushl $0
call exit
.end



It works, i.e., exits without any errors with the ld-linux.so that
exists on all my systems except the Red Hat 9 system.

On the Red Hat 9 system, it will segfault.


Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips).
Why is the government concerned about the lunatic fringe? Think about it.

2003-06-06 20:57:15

by Richard Henderson

[permalink] [raw]
Subject: Re: Shared Library starter, ld.so

On Fri, Jun 06, 2003 at 07:34:50AM -0400, Richard B. Johnson wrote:
> .section .text
> .global _start
> .type _start,@function
> _start: call *%edx
> pushl $0
> call exit
> .end
...
> On the Red Hat 9 system, it will segfault.

[vsop:~] gcc -nostartfiles zz.s
[vsop:~] ./a.out
[vsop:~] echo $?
0
[vsop:~] cat /etc/redhat-release
Red Hat Linux release 9 (Shrike)

Works For Me.


r~