This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


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

Q: ld scripts for multisegment ELF dynamic executables?



Hello All binutils power users and developpers,

My plateform is Linux/Debian (testing=sid) x86 (AMD/K6 II/400), kernel
2.2.18. I used both the debian ld (GNU ld 2.10.91) and a freshly
compiled and installed (in /usr/local) binutils-2.10.91.0.2.tar.gz

I am computer educated and knows quite well the ELF format; but I do
not know the internals of binutils and ld.

My goal is to produce an ELF dynamically linked executable with more
than the 2 usual text and data segments (segments are what describes
the ELF program header, and are memory mapped by the execve system
call).

I would like to have four segments (excluding the PHDR and DYNAMIC) -
the 2 usual ones and 2 own ones.

  the usual text (read-only, executable) segment (containing code and
  readonly data)

  the usual data (read & write) segment (containing initialized
  [.data...] and unitialized [.bss] 

  my own TEXTHEAP segment is read-only, executable, and should start
  at a fixed virtual memory address (say 0x60000000)

  my own DATAHEAP segment is read and write and executable, and should
  start at a fixed virtual memory address (say 0x70000000)

The intent is to have an ELF executable (linked ot shared objects such
as /lib/libc.so.6 and /usr/X11/lib/libX11.so*) which contains C
compiled code and data (e.g. some GUI code using gtk and X11) and also
a "persisted" heap of a Lisp-like (compiled and garbage-collected)
language implementation. The rationale of having my own segments (and
not using for my heap the usual data and text segments) at fixed
addresses is that exporting my heap (with eventually its relocation)
would be much easier than the unexecelf routine of Emacs or Xemacs or
the dldump call available on Solaris.

I have no doubt that the Linux kernel supports more than 2 segments
(in the execve system call and kernel source file
linux/fs/binfmt_elf.c).


I tried to code the following ld script (which is an extension of
/usr/lib/ldscripts/elf_i386.x) :::

############################################################
/* file Qish/Basic/ldscript */

/* heavily copied from /usr/lib/ldscripts/elf_i386.x on my Debian/sid system */

OUTPUT_FORMAT("elf32-i386", "elf32-i386",
	      "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/X11R6/lib);

textheap_base = ABSOLUTE(0x60000000) ;
dataheap_base = ABSOLUTE(0x70000000) ;

PHDRS {
       headers PT_PHDR PHDRS ;
       interp PT_INTERP ;
       text PT_LOAD FILEHDR PHDRS ;
       data PT_LOAD ;
       dynamic PT_DYNAMIC ;
       note PT_NOTE ;
       textheap PT_LOAD AT (0x60000000) FLAGS (5) /*r-x*/;
       dataheap PT_LOAD AT (0x70000000) FLAGS (7) /*rwx*/ ;
}

SECTIONS
{

  /***************** plain text segment ****************/
  /* Read-only sections, merged into text segment: */
  . = 0x08048000 + SIZEOF_HEADERS;
  .interp     : { *(.interp) 	} :text :interp
  .hash          : { *(.hash)		} :text
  .dynsym        : { *(.dynsym)		}
  .dynstr        : { *(.dynstr)		}
  .gnu.version   : { *(.gnu.version)	}
  .gnu.version_d   : { *(.gnu.version_d)	}
  .gnu.version_r   : { *(.gnu.version_r)	}
  .rel.init      : { *(.rel.init)	}
  .rela.init     : { *(.rela.init)	}
  .rel.text      :
    {
      *(.rel.text)
      *(.rel.text.*)
      *(.rel.gnu.linkonce.t.*)
    }
  .rela.text     :
    {
      *(.rela.text)
      *(.rela.text.*)
      *(.rela.gnu.linkonce.t.*)
    }
  .rel.fini      : { *(.rel.fini)	}
  .rela.fini     : { *(.rela.fini)	}
  .rel.rodata    :
    {
      *(.rel.rodata)
      *(.rel.rodata.*)
      *(.rel.gnu.linkonce.r.*)
    }
  .rela.rodata   :
    {
      *(.rela.rodata)
      *(.rela.rodata.*)
      *(.rela.gnu.linkonce.r.*)
    }
  .rel.data      :
    {
      *(.rel.data)
      *(.rel.data.*)
      *(.rel.gnu.linkonce.d.*)
    }
  .rela.data     :
    {
      *(.rela.data)
      *(.rela.data.*)
      *(.rela.gnu.linkonce.d.*)
    }
  .rel.ctors     : { *(.rel.ctors)	}
  .rela.ctors    : { *(.rela.ctors)	}
  .rel.dtors     : { *(.rel.dtors)	}
  .rela.dtors    : { *(.rela.dtors)	}
  .rel.got       : { *(.rel.got)		}
  .rela.got      : { *(.rela.got)		}
  .rel.sdata     :
    {
      *(.rel.sdata)
      *(.rel.sdata.*)
      *(.rel.gnu.linkonce.s.*)
    }
  .rela.sdata     :
    {
      *(.rela.sdata)
      *(.rela.sdata.*)
      *(.rela.gnu.linkonce.s.*)
    }
  .rel.sbss      :
    { 
      *(.rel.sbss)
      *(.rel.sbss.*)
      *(.rel.gnu.linkonce.sb.*)
    }
  .rela.sbss     :
    {
      *(.rela.sbss)
      *(.rela.sbss.*)
      *(.rel.gnu.linkonce.sb.*)
    }
  .rel.sdata2    : 
    { 
      *(.rel.sdata2)
      *(.rel.sdata2.*)
      *(.rel.gnu.linkonce.s2.*)
    }
  .rela.sdata2   : 
    {
      *(.rela.sdata2)
      *(.rela.sdata2.*)
      *(.rela.gnu.linkonce.s2.*)
    }
  .rel.sbss2     : 
    { 
      *(.rel.sbss2)	
      *(.rel.sbss2.*)
      *(.rel.gnu.linkonce.sb2.*)
    }
  .rela.sbss2    : 
    { 
      *(.rela.sbss2)	
      *(.rela.sbss2.*)
      *(.rela.gnu.linkonce.sb2.*)
    }
  .rel.bss       : 
    { 
      *(.rel.bss)
      *(.rel.bss.*)
      *(.rel.gnu.linkonce.b.*)
    }
  .rela.bss      : 
    { 
      *(.rela.bss)
      *(.rela.bss.*)
      *(.rela.gnu.linkonce.b.*)
    }
  .rel.plt       : { *(.rel.plt)		}
  .rela.plt      : { *(.rela.plt)		}
  .init          : 
  { 
    KEEP (*(.init))
  } =0x9090
  .plt      : { *(.plt)	}
  .text      :
  {
    *(.text)
    *(.text.*)
    *(.stub)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
    *(.gnu.linkonce.t.*)
  } =0x9090
  .fini      :
  {
    KEEP (*(.fini))
  } =0x9090
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);
  .rodata   : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) }
  .rodata1   : { *(.rodata1) }
  .sdata2   : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
  .sbss2   : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }

  /**************** plain data segment ****************/
  /* Adjust the address for the data segment.  We want to adjust up to
     the same address within the page on the next page up.  */
  . = ALIGN(0x1000) + (. & (0x1000 - 1));
  .data    :
  {
    *(.data)
    *(.data.*)
    *(.gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  } :data
  .data1   : { *(.data1) }
  .eh_frame : { KEEP (*(.eh_frame)) }
  .gcc_except_table : { *(.gcc_except_table) }
  .ctors   : 
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    /* We don't want to include the .ctor section from
       from the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }
   .dtors         :
  {
    KEEP (*crtbegin.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  }
  .got		  : { *(.got.plt) *(.got) }
  _edata = .;
  PROVIDE (edata = .);
  __bss_start = .;
  .sbss      :
  {
    PROVIDE (__sbss_start = .);
    PROVIDE (___sbss_start = .);
    *(.dynsbss)
    *(.sbss)
    *(.sbss.*)
    *(.gnu.linkonce.sb.*)
    *(.scommon)
    PROVIDE (__sbss_end = .);
    PROVIDE (___sbss_end = .);
  }
  .bss       :
  {
   *(.dynbss)
   *(.bss)
   *(.bss.*)
   *(.gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.  */
   . = ALIGN(32 / 8);
  }
  . = ALIGN(32 / 8);
  _end = .;
  PROVIDE (end = .);
  .dynamic       : 
	{ KEEP(*(.dynamic)) } :data :dynamic 

  /***************** read-only text heap *****************/
  . = ALIGN(0x10000);
  TEXTHEAP textheap_base 
  () : { 
/*0xF4 is the priviledged HLT instruction*/
     LONG(0xF4F4F4F4);
     LONG(0xF4F4F4F4);
     FILL(0xF4F4F4F4); 
     textheap_start = . ;
     KEEP(*(TEXTHEAP))
     LONG(0xF4F4F4F4);
     LONG(0xF4F4F4F4);
     FILL(0);
  } :textheap
  textheap_end = . ;
  . = ALIGN(0x100);
  .rel.TEXTHEAP : {
    
    *(.rel.TEXTHEAP)
  }
  . = ALIGN(0x100);
  .rel.DATAHEAP : {
    *(.rel.DATAHEAP)
  }
  
  /***************** read-write data heap *****************/
  . = ALIGN(0x10000);
  DATAHEAP dataheap_base 
  (): { 
     dataheap_start = . ;
     KEEP(*(DATAHEAP))
     LONG(0);
     FILL(0);
     dataheap_end = . ;
  } :dataheap 
  . = ALIGN(0x1000);

  /***************** debugging and info ****************/
  .note : { 
      *(.note)
      *(.note.*) 
  } :text :note

  /* Stabs debugging sections.  */
  .stab 0 : { *(.stab) } 
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
  /* DWARF debug sections are not needed */
}


############################################################


I tried this tiny main2.c program

/* file Qish/main2.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <dlfcn.h>

int main(int argc, char** argv)
{
  static char line[400];
  puts("in Qish/main2.c::" __DATE__ "," __TIME__);
  if (argc>1) {
    FILE* f=0;
    void *h= dlopen(argv[1], RTLD_NOW);
    printf("after dlopen %s h=%p\n", argv[1], h);
    f = fopen("/proc/self/maps", "r");
    if (f) {
      while (!feof(f)) {
	fgets(line, sizeof(line), f);
	fputs(line, stdout);
      };
      fclose(f);
    };
  }
  return 0;
}

############################################################

I compiled main2.c with
gcc -g -O -c main2.c

then I linked with

ld -export-dynamic -dynamic-linker /lib/ld-linux.so.2 -o /tmp/q2 \
/usr/lib/crt1.o /usr/lib/crti.o \
/usr/lib/gcc-lib/i386-linux/2.95.3/crtbegin.o \
-L/usr/lib/gcc-lib/i386-linux/2.95.3 main2.o -ldl -lm /lib/libc.so.6 \
-lgcc -lc -lgcc /usr/lib/gcc-lib/i386-linux/2.95.3/crtend.o \
/usr/lib/crtn.o -T ldscript

I've got no compile- or link-time errors. But running the binary
/tmp/q2 core dumps. And even running ldd /tmp/q2 gives ldd:
/lib/ld-linux.so.2 exited with unknown exit code (139) 


Any clues or hints?

(perhaps giving me the default PHDRS of ld might help me).

Regards

--

Basile STARYNKEVITCH -- http://perso.wanadoo.fr/starynkevitch/basile/
email: basile dot starynkevitch at wanadoo dot fr (France)
alias: basile at tunes dot org       host: http://lesours.dyndns.org/
8, rue de la Faïencerie, 92340 Bourg La Reine, phone: 1.46.65.45.53


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