Subject: kernel linking with binutils 2.8
To: None <port-pmax@NetBSD.ORG>
From: Arne Henrik Juul <arnej@stud.math.ntnu.no>
List: port-pmax
Date: 05/22/1997 02:33:24
I recently upgraded using the latest (I hope) snapshot, which
included -970314 binutils.  Being the kind of person who likes
to compile everything from source myself, I've compiled
straight binutils 2.8 on my NetBSD/pmax -current box.  I then
proceeded to try to get the linker from binutils 2.8 to link
kernels.  This works with two changes: Instead of the -Ttext
option, I use a simple linker script, and I have to set the GP
variable in the Makefile.

The reason for the first change is "well-known", it's because
the default linker scripts uses SIZEOF_HEADERS, which estimates
the number of program load-time segments using a simple
formula, and when it turns out at a later time that the
estimate was too low this means that there's not enough space
in the header.  It's theoretically a hard problem (like trying
to predict the page numbers for chapters when making a table of
contents, but the predictions themselves may change the length
of the TOC and thereby the placement of the chapters, for those
who've tried to solve this type of problem.)  It's probably
possibly to just kludge it by making a probably-too-high
estimate instead of the current probably-right-but-may-be-too-low.

However, for our purposes using a linker script is probably
just as well, and gives us better control over sections and
placement as well, so I advocate this solution.  The one I've
used some times now is appended at the bottom; this will make
elf2aout warn about an intersegment gap between 4k and 8k, if
everything works right.  It can probably be simplified a bit
more, especially the debug sections (I haven't compiled a
kernel with debugging so I've just let that part be).

The other issue: the -G option.  It is my understanding that
the compiler now defaults to -G 0 which causes it to never
put data in .sdata/.sbss sections.  However, when compiling
kernel it will still get some GPREL16 relocs and the assembler
will put some external data in .scommon sections, probably
because of -mno-half-pic and/or that the assembler has *not*
been told about the -G 0 default. (Should it be? and how?)

When these data are (in the object file where they are defined)
put in the .data section, things won't work (it gives error
messages about truncating relocs).  Since the kernel doesn't
use shared libraries :-) it should be safe to use -G 8 or
maybe even higher, and this may be a performance boost as well
(if I've understood how GP-relative addressing works).

I've tried both -G 4 and -G 8 and both seem to work well, so I
think GP=-G 8 should be added to Makefile.pmax; however GP=-G 0
also works (since the assembler then actually gets the option).

One last thing:  Since binutils 2.8 is now released (and 2.8.1
will probably come out soonish), can this be imported into the
NetBSD source tree, I would hope for usage by the pmax and
alpha ports soon, but hopefully with the option of producing
ELF-format binaries for other NetBSD ports later on?  And gdb
for pmax, could that use the bfd library from binutils 2.8?

Well, that's it for tonight from Norway,
  -  Arne H. J.
And here's the linker script I use, I put it in
/sys/arch/pmax/conf/kern.ldscript and set LINKFLAGS to
be just "-T ${PMAX}/conf/kern.ldscript -e start".

OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips",
	      "elf32-littlemips")
OUTPUT_ARCH(mips)
ENTRY(_start)
SEARCH_DIR(/lib);
/* Do we need any of these?
   __DYNAMIC = 0;    */
_DYNAMIC_LINK = 0;
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  . = 0x80030000;
  .text      :
  {
    _ftext = . ;
    *(.text)
    *(.gnu.warning)
  } =0
  _etext = .;
  PROVIDE (etext = .);
  .rodata    : { *(.rodata)  }
  .reginfo : { *(.reginfo) }
  . = . + 0x1000;
  .data    :
  {
    _fdata = . ;
    *(.data)
    CONSTRUCTORS
  }
  _gp = ALIGN(16) + 0x7ff0;
  .lit8 : { *(.lit8) }
  .lit4 : { *(.lit4) }
  .sdata     : { *(.sdata) }
  _edata  =  .;
  PROVIDE (edata = .);
  __bss_start = .;
  _fbss = .;
  .sbss      : { *(.sbss) *(.scommon) }
  .bss       :
  {
   *(.bss)
   *(COMMON)
  }
  _end = . ;
  PROVIDE (end = .);
  /* These are needed for ELF backends which have not yet been
     converted to the new style linker.  */
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  /* DWARF debug sections.
     Symbols in the .debug DWARF section are relative to the beginning of the
     section so we begin .debug at 0.  It's not clear yet what needs to happen
     for the others.   */
  .debug          0 : { *(.debug) }
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  .line           0 : { *(.line) }
  /* These must appear regardless of  .  */
  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
}