Subject: ELF/Modutils problem

From: Brady Brown <[email-masked]>
Date: Tue, 19 Sep 2000 18:03:08 -0600

I'm having trouble getting modutils 2.3.10 to work on a little endian
MIPS box running a 2.4.0-test3 kernel. I am cross compiling the kernel
and modules on an i386 using egcs1.0.3a-2 and binutils2.8.1-1. It
appears that the symbol table format in the ELF file created by
mipsel-linux-gcc during a module build is incorrect.

As I read the ELF 1.1 spec - all symbols with STB_LOCAL bindings should
precede all other symbols (weak and global) in the symbol table. Then
the symbol table section's sh_info section header member holds the
symbol table index for the first non-local symbol (and thus can then be
used to determine the number of local symbols). Using the readelf
utility on a generated module shows that the local symbols are not
grouped together before all other symbols but are intermixed though out
the symbol table, and the sh_info field in the header is not set to the
first non-local symbol index.

When insmod runs it malloc's memory equal to the sh_info field and then
begins to populate the local symbols into it. Because of the bad symbol
ordering and incorrect value in sh_info, the malloc'd memory is far to
small to hold all of the local symbols so memory gets blasted and the
module fails to load correctly.

As a side test I tried to incrementally link the module.o file using
mipsel-linux-ld -r module.o -o module. Viewing the ELF output from this
stage showed a correct symbol ordering and sh_info field so it appears
that the linker is generating the correct format for the symbol table
(problem with gcc only?). Has this problem been addressed/resolved? Any
suggestions?

---

From: Keith Owens <[email-masked]>
Date: Wed, 20 Sep 2000 11:24:25 +1100

On Tue, 19 Sep 2000 18:03:08 -0600, 
Brady Brown <[email-masked]> wrote:
>precede all other symbols (weak and global) in the symbol table.

modutils 2.3.11 includes a sanity check on the number of local symbols
precisely because of this MIPS problem.  I agree with you that mips gcc
is violating the ELF standard, 2.3.11 just detects this and issues an
error message instead of overwriting memory but gcc needs to be fixed.
BTW, you might want to upgrade to modutils >= 2.3.15, there are some
MIPS patches in modutils 2.3.15.

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 21 Sep 2000 15:36:31 +0200

> error message instead of overwriting memory but gcc needs to be fixed.

And gcc has nothing to with it so it won't need to be fixed ...

  Ralf

---

From: Keith Owens <[email-masked]>
Date: Fri, 22 Sep 2000 20:57:00 +1100

On Thu, 21 Sep 2000 15:36:31 +0200, 
>And gcc has nothing to with it so it won't need to be fixed ...

Point taken, I should have said the MIPS toolchain instead of gcc.
Something in the toolchain is generating an ELF object that does not
follow the rules.  Can we catch someone's attention to get it fixed?

---

From: Ralf Baechle <[email-masked]>
Date: Fri, 22 Sep 2000 15:31:56 +0200

> follow the rules.  Can we catch someone's attention to get it fixed?

Ulf Carlsson <[email-masked]> is currently maintaining binutils.
Ulf, you got the bandwidth to take a look at this?  After a look over the
gas code it's not obvious to my why this doesn't work on MIPS but on
all the other architectures, you probably know the internals of this beast
better than I do.

  Ralf

---

From: Brady Brown <[email-masked]>
Date: Fri, 22 Sep 2000 09:23:36 -0600

> all the other architectures, you probably know the internals of this beast

I'm not sure what exact piece of the tool chain forms the un-linked elf file,
but as I stated originally the symbol table in the .o file is incorrect after
compiling and then if I do an incremental link (-r) the symbol table and length
pointer have been corrected. Based upon this it looks like the output from the
linker is correct, but the output from the earlier stage is wrong.

---

From: Ralf Baechle <[email-masked]>
Date: Sat, 23 Sep 2000 23:06:32 +0200

On Fri, Sep 22, 2000 at 09:23:36AM -0600, Brady Brown wrote:

> compiling and then if I do an incremental link (-r) the symbol table and
> length pointer have been corrected. Based upon this it looks like the output
> from the linker is correct, but the output from the earlier stage is wrong.

It's the assembler as below text case demonstrates.

  Ralf

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-09-23 23:03 MEST by <[email-masked]>.
# Source directory was `/home/ralf/src/binutils'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#     37 -rw-rw-r-- nuke-as-01/s.s
#    161 -rw-r--r-- nuke-as-01/Makefile
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh01696; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= nuke-as-01/s.s ==============
if test ! -d 'nuke-as-01'; then
  $echo 'x -' 'creating directory' 'nuke-as-01'
  mkdir 'nuke-as-01'
fi
if test -f 'nuke-as-01/s.s' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'nuke-as-01/s.s' '(file already exists)'
else
  $echo 'x -' extracting 'nuke-as-01/s.s' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'nuke-as-01/s.s' &&
X	.globl	x1
x1:	.word	x1
x2:	.word	x2
SHAR_EOF
  (set 20 00 09 22 02 42 43 'nuke-as-01/s.s'; eval "$shar_touch") &&
  chmod 0664 'nuke-as-01/s.s' ||
  $echo 'restore of' 'nuke-as-01/s.s' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'nuke-as-01/s.s:' 'MD5 check failed'
509bca5a5362c487c805dbc79d9d32a8  nuke-as-01/s.s
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'nuke-as-01/s.s'`"
    test 37 -eq "$shar_count" ||
    $echo 'nuke-as-01/s.s:' 'original size' '37,' 'current size' "$shar_count!"
  fi
fi
# ============= nuke-as-01/Makefile ==============
if test -f 'nuke-as-01/Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'nuke-as-01/Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'nuke-as-01/Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'nuke-as-01/Makefile' &&
target = mips64-linux-
AS = $(target)as
OBJDUMP = $(target)objdump
READELF = $(target)readelf
X
CFLAGS =
X
all:	s.o
X	$(READELF) -s $^
X
clean distclean:
X	rm -f s.o
SHAR_EOF
  (set 20 00 09 21 15 47 28 'nuke-as-01/Makefile'; eval "$shar_touch") &&
  chmod 0644 'nuke-as-01/Makefile' ||
  $echo 'restore of' 'nuke-as-01/Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'nuke-as-01/Makefile:' 'MD5 check failed'
4d263e9d27b40dbb44f9fadc00160fa5  nuke-as-01/Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'nuke-as-01/Makefile'`"
    test 161 -eq "$shar_count" ||
    $echo 'nuke-as-01/Makefile:' 'original size' '161,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh01696
exit 0

---

From: Ulf Carlsson <[email-masked]>
Date: 23 Sep 2000 15:03:50 -0700

> It's the assembler as below text case demonstrates.

Thanks.  I'll take a look at it.  I remember that I've looked at this
problem once before.

Ulf

---

From: Ralf Baechle <[email-masked]>
Date: Wed, 27 Sep 2000 12:34:09 +0200

> Thanks.  I'll take a look at it.  I remember that I've looked at this

This piece of gold in bfd/elf32-mips.c seems to be the problem:

/* Determine whether a symbol is global for the purposes of splitting
   the symbol table into global symbols and local symbols.  At least
   on Irix 5, this split must be between section symbols and all other
   symbols.  On most ELF targets the split is between static symbols
   and externally visible symbols.  */

/*ARGSUSED*/
static boolean
mips_elf_sym_is_global (abfd, sym)
     bfd *abfd ATTRIBUTE_UNUSED;
     asymbol *sym;
{
  return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
}

So our objects are correct, just IRIX flavoured at this point ...  Now
for a proper fix I think I need somebody who knows IRIX ELF like his
pocket ...

  Ralf