Jeremy White wrote:
> 
> Gav sparked me to go look and see how I could pull argc/argv
> out during the constructor phase of library load,
> and I believe I have found a method that should work,
> at least for elf/glibc implementations.

I'm glad I sparked some investigation, but on further reflection and
looking at code, I'm not sure that this is actually possible.

> The good news is that _init is passed argc, argv, and environp.

The glibc source code certainly seems to assume that this is the
case, but I've been looking at the ld-linux sources, and I don't 
see the mechanism it uses to do this:

The code in question (in d-link/boot1.c) looks like this:

  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
    {
      /* Apparently crt1 for the application is responsible for handling this.
       * We only need to run the init/fini for shared libraries
       */
      if (tpnt->libtype == program_interpreter ||
        tpnt->libtype == elf_executable) continue;
      if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
      tpnt->init_flag |= INIT_FUNCS_CALLED;
      
      if(tpnt->dynamic_info[DT_INIT]) {
        _dl_elf_init = (int (*)(void)) (tpnt->loadaddr + 
                                    tpnt->dynamic_info[DT_INIT]);
        (*_dl_elf_init)();
      }
    .
    .
    .

It doesn't appear to be able to pass argc and argv until it actually
loads the executable start code:

  /* OK we are done here.  Turn out the lights, and lock up. */
  _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY];


  /*
   * Transfer control to the application.
   */
  START();

Where START() is a macro that cleans up the the local stack for
the boot function, leaving the stack with the arguments passed
from the kernel.

To further confound things though, when I actually tried making
a simple shared lib with an _init function, it *did* get argc
and argv, but as you suggested, libc then went wonky because
it didn't get initialized properly - note the line above that reads:

      tpnt->init_flag |= INIT_FUNCS_CALLED;

This is what's causing it to stop once it's run one _init function.

I also just tried getting the address for the libc _init function
from dlsym and calling through to that from the test library,
but that didn't seem to work, though I did see it travel down
into the bowels of glibc initialization.

> The one thing I can't clearly assess is whether this method
> is portable to all of the platforms we care about.

The _init thing is I believe fairly gcc/ELF centric.  It works
because the linker twigs that it needs to put a DT_INIT tag into
the ELF headers, pointed to that function.  

> One advantage to Alexandre's method (let Wine run, do
> a LoadLibrary(), GetProcAddress("WinMain"), start the app),
> is that it is more portable.

I suppose - but it feels wrong to build a winelib app foo, and
end up with a 'foo' and a 'foo.so', where there's no real code in 
'foo'.

-Gav

-- 
Gavriel State
CEO
TransGaming Technologies Inc.
[EMAIL PROTECTED]

Reply via email to