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]

IA-64 gp problem with PROVIDE and linker relaxation conflict


We are having problems with the gp value getting set incorrectly when GNU ld
links objects produced by the Intel compiler.  I got a pointer from Intel
about where the problem is, and was able to produce a testcase that
demonstrates the problem.

If I create a program that explicitly refers to the symbol __gp, and has
such a large text section that there are out-of-range calls and thus
requires -relax, then the value of __gp ends up wrong after the link.

The IA-64 linker script uses PROVIDE to set the value of __gp.  There is code
in file ld/ldexp.c function exp_fold_tree case etree_provide that tries to
make sure that we don't set the value if an object file already set the value.
The net effect however is that the value can only be set once.

When relaxation is enabled, there is code that repeatedly calls 
lang_size_sections and lang_do_assignments.  This is in file ld/ldlang.c
function lang_process, in the command_line.relax if statement.  The first
time we call lang_size_sections, we give __gp a value.  Then we make the
text section 48 bytes bigger to handle each out-of-range branch.  This in turn
increases the start address of the data section which immediately follows
text section mod the max page size (or something like that).  Next time we
compute a value for __gp, it is bigger, but we don't use the value because
__gp has already been assigned to once already, and a provided value can only
be assigned to once.  Now __gp is wrong.

If you have a big enough gp section, and/or enough out-of-range calls, then
after linker is done the gp value won't cover the small data section.  The
Intel testcases are very large commercial applications, and this is IA-64
code we are talking about, which makes them even larger.

I think we need some way to tell whether a provided value was defined by an
object file or defined by an earlier call to exp_fold_tree.  In the latter
case, we do want to replace the old value with the new value.  In the former
case, we do not want to change the value.

Or perhaps we can defer assigning a value until we are done relaxing.
I don't know if this is safe though, since if symbol values can affect section
sizes then it won't work.

Here is a small testcase.  When I run this on an ia64-linux machine I get

objdump -x tmp | grep .got
 16 .got          00000078  6000000000008400  6000000000008400  01f58400  2**3
6000000000008400 l    d  .got	0000000000000000              
6000000000008400 g     O .got	0000000000000000              _GLOBAL_OFFSET_TABLE_
objdump -x tmp | grep __gp
60000000002083d0 g     O *ABS*	0000000000000000              __gp

Notice that the __gp value is 48 bytes too small, because the linker script
sets it to .got + 0x200000.

#!/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 2001-02-12 20:28 PST by <wilson@bletchleypark.cygnus.com>.
# Source directory was `/blp/wilson/tmp2'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    205 -rw-rw-r-- Makefile
#    229 -rw-rw-r-- gen.c
#     52 -rw-rw-r-- tmp.c
#
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 _sh20963; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
all: tmp
X	objdump -x tmp | grep .got
X	objdump -x tmp | grep __gp
X
gen: gen.c
X
tmp2.c: gen
X	./gen > tmp2.c
X
tmp: tmp.o tmp2.o
X	gcc -o tmp -Wl,-relax tmp.o tmp2.o
X
clean:
X	rm -rf tmp.o tmp2.o tmp2.c tmp gen
SHAR_EOF
  (set 20 01 02 12 20 16 10 'Makefile'; eval "$shar_touch") &&
  chmod 0664 'Makefile' ||
  $echo 'restore of' '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 'Makefile:' 'MD5 check failed'
24758ae25fc8e607896f2f9d3364e061  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`"
    test 205 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '205,' 'current size' "$shar_count!"
  fi
fi
# ============= gen.c ==============
if test -f 'gen.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'gen.c' '(file already exists)'
else
  $echo 'x -' extracting 'gen.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'gen.c' &&
main()
{
X  int i;
X
X  printf ("\
main()\n\
{\n\
X  int i = 0;\n");
X
X  for (i = 0; i < 1000; i++)
X    {
X      printf ("  asm (\".align 32768\");\n");
X      printf ("  i++;\n");
X    }
X
X  printf ("\
X  sub ();\n\
}\n");
X
X  return 0;
}
SHAR_EOF
  (set 20 01 02 12 20 16 17 'gen.c'; eval "$shar_touch") &&
  chmod 0664 'gen.c' ||
  $echo 'restore of' 'gen.c' '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 'gen.c:' 'MD5 check failed'
7671dae38416ba3f026f0d9502357385  gen.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'gen.c'`"
    test 229 -eq "$shar_count" ||
    $echo 'gen.c:' 'original size' '229,' 'current size' "$shar_count!"
  fi
fi
# ============= tmp.c ==============
if test -f 'tmp.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'tmp.c' '(file already exists)'
else
  $echo 'x -' extracting 'tmp.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'tmp.c' &&
extern int __gp;
int gb;
X
sub ()
{
X  return __gp;
}
SHAR_EOF
  (set 20 01 02 12 19 51 54 'tmp.c'; eval "$shar_touch") &&
  chmod 0664 'tmp.c' ||
  $echo 'restore of' 'tmp.c' '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 'tmp.c:' 'MD5 check failed'
c63c0cc00850497bc8d41d1d2f935bf9  tmp.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'tmp.c'`"
    test 52 -eq "$shar_count" ||
    $echo 'tmp.c:' 'original size' '52,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh20963
exit 0


Jim



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