diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index cee77f47b4..5656208407 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,19 @@ +Thu Oct 27 17:30:12 1994 Ian Lance Taylor + + * ld-shared: New directory, with new files to test generating ELF + shared libraries. + + * lib/ld.exp (default_ld_compile): If the compilation worked, but + no object file was created, check to see if the compiler foolishly + ignored the -o switch when compiling, and move the resulting + object if it did. + +Thu Sep 29 12:36:51 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * VMS does not permits `.' in directory names. Renamed + ld.bootstrap to ld-bootstrap, ld.cdtest to ld-cdtest, and + ld.scripts to ld-scripts. + Wed Sep 28 12:18:54 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) * config/default.exp: Set variables as and nm. Create tmpdir if diff --git a/ld/testsuite/ld-shared/.Sanitize b/ld/testsuite/ld-shared/.Sanitize new file mode 100644 index 0000000000..46b301bca3 --- /dev/null +++ b/ld/testsuite/ld-shared/.Sanitize @@ -0,0 +1,40 @@ +# .Sanitize for ld dejagnu testsuites + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order.. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this directory. + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Do-last:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +main.c +sh1.c +sh2.c +shared.dat +shared.exp + +Things-to-lose: + +# The lines between the "Do-last:" line and the end of the file +# are executed as a /bin/sh shell script after everything else is +# done. + +Do-last: + +#eof diff --git a/ld/testsuite/ld-shared/main.c b/ld/testsuite/ld-shared/main.c new file mode 100644 index 0000000000..7003c62f3d --- /dev/null +++ b/ld/testsuite/ld-shared/main.c @@ -0,0 +1,63 @@ +/* This is the main program for the shared library test. */ + +#include + +int mainvar = 1; +int overriddenvar = 2; +extern int shlibvar1; + +extern int shlib_mainvar (); +extern int shlib_overriddenvar (); +extern int shlib_shlibvar1 (); +extern int shlib_shlibvar2 (); +extern int shlib_shlibcall (); +extern int shlib_maincall (); +extern int shlib_checkfunptr1 (); +extern int shlib_checkfunptr2 (); +extern int (*shlib_getfunptr1 ()) (); +extern int (*shlib_getfunptr2 ()) (); +extern int shlib_check (); + +/* This function is called by the shared library. */ + +int +main_called () +{ + return 6; +} + +int +main () +{ + int (*p) (); + + printf ("mainvar == %d\n", mainvar); + printf ("overriddenvar == %d\n", overriddenvar); + printf ("shlibvar1 == %d\n", shlibvar1); + printf ("shlib_mainvar () == %d\n", shlib_mainvar ()); + printf ("shlib_overriddenvar () == %d\n", shlib_overriddenvar ()); + printf ("shlib_shlibvar1 () == %d\n", shlib_shlibvar1 ()); + printf ("shlib_shlibvar2 () == %d\n", shlib_shlibvar2 ()); + printf ("shlib_shlibcall () == %d\n", shlib_shlibcall ()); + printf ("shlib_maincall () == %d\n", shlib_maincall ()); + printf ("shlib_checkfunptr1 (shlib_mainvar) == %d\n", + shlib_checkfunptr1 (shlib_mainvar)); + printf ("shlib_checkfunptr2 (main_called) == %d\n", + shlib_checkfunptr2 (main_called)); + p = shlib_getfunptr1 (); + printf ("shlib_getfunptr1 () "); + if (p == shlib_mainvar) + printf ("=="); + else + printf ("!="); + printf (" shlib_mainvar\n"); + p = shlib_getfunptr2 (); + printf ("shlib_getfunptr2 () "); + if (p == main_called) + printf ("=="); + else + printf ("!="); + printf (" main_called\n"); + printf ("shlib_check () == %d\n", shlib_check ()); + return 0; +} diff --git a/ld/testsuite/ld-shared/sh1.c b/ld/testsuite/ld-shared/sh1.c new file mode 100644 index 0000000000..6d5b669b55 --- /dev/null +++ b/ld/testsuite/ld-shared/sh1.c @@ -0,0 +1,133 @@ +/* This is part of the shared library ld test. This file becomes part + of a shared library. */ + +/* This variable is supplied by the main program. */ +extern int mainvar; + +/* This variable is defined in the shared library, and overridden by + the main program. */ +int overriddenvar = -1; + +/* This variable is defined in the shared library. */ +int shlibvar1 = 3; + +/* This variable is defined by another object in the shared library. */ +extern int shlibvar2; + +/* These functions return the values of the above variables as seen in + the shared library. */ + +int +shlib_mainvar () +{ + return mainvar; +} + +int +shlib_overriddenvar () +{ + return overriddenvar; +} + +int +shlib_shlibvar1 () +{ + return shlibvar1; +} + +int +shlib_shlibvar2 () +{ + return shlibvar2; +} + +/* This function calls a function defined by another object in the + shared library. */ + +extern int shlib_shlibcalled (); + +int +shlib_shlibcall () +{ + return shlib_shlibcalled (); +} + +/* This function calls a function defined by the main program. */ + +extern int main_called (); + +int +shlib_maincall () +{ + return main_called (); +} + +/* This function is passed a function pointer to shlib_mainvar. It + confirms that the pointer compares equally. */ + +int +shlib_checkfunptr1 (p) + int (*p) (); +{ + return p == shlib_mainvar; +} + +/* This function is passed a function pointer to main_called. It + confirms that the pointer compares equally. */ + +int +shlib_checkfunptr2 (p) + int (*p) (); +{ + return p == main_called; +} + +/* This function returns a pointer to shlib_mainvar. */ + +int +(*shlib_getfunptr1 ()) () +{ + return shlib_mainvar; +} + +/* This function returns a pointer to main_called. */ + +int +(*shlib_getfunptr2 ()) () +{ + return main_called; +} + +/* This function makes sure that constant data and local functions + work. */ + +#ifndef __STDC__ +#define const +#endif + +static int i = 6; +static const char *str = "Hello, world\n"; + +int +shlib_check () +{ + const char *s1, *s2; + + if (i != 6) + return 0; + + /* To isolate the test, don't rely on any external functions, such + as strcmp. */ + s1 = "Hello, world\n"; + s2 = str; + while (*s1 != '\0') + if (*s1++ != *s2++) + return 0; + if (*s2 != '\0') + return 0; + + if (shlib_shlibvar1 () != 3) + return 0; + + return 1; +} diff --git a/ld/testsuite/ld-shared/sh2.c b/ld/testsuite/ld-shared/sh2.c new file mode 100644 index 0000000000..013a4e0994 --- /dev/null +++ b/ld/testsuite/ld-shared/sh2.c @@ -0,0 +1,14 @@ +/* This is part of the shared library ld test. This file becomes part + of a shared library. */ + +/* This variable is defined here, and referenced by another file in + the shared library. */ +int shlibvar2 = 4; + +/* This function is called by another file in the shared library. */ + +int +shlib_shlibcalled () +{ + return 5; +} diff --git a/ld/testsuite/ld-shared/shared.dat b/ld/testsuite/ld-shared/shared.dat new file mode 100644 index 0000000000..12477e2173 --- /dev/null +++ b/ld/testsuite/ld-shared/shared.dat @@ -0,0 +1,14 @@ +mainvar == 1 +overriddenvar == 2 +shlibvar1 == 3 +shlib_mainvar () == 1 +shlib_overriddenvar () == 2 +shlib_shlibvar1 () == 3 +shlib_shlibvar2 () == 4 +shlib_shlibcall () == 5 +shlib_maincall () == 6 +shlib_checkfunptr1 (shlib_mainvar) == 1 +shlib_checkfunptr2 (main_called) == 1 +shlib_getfunptr1 () == shlib_mainvar +shlib_getfunptr2 () == main_called +shlib_check () == 1 diff --git a/ld/testsuite/ld-shared/shared.exp b/ld/testsuite/ld-shared/shared.exp new file mode 100644 index 0000000000..d836a2ad1c --- /dev/null +++ b/ld/testsuite/ld-shared/shared.exp @@ -0,0 +1,146 @@ +# Expect script for ld-shared tests +# Copyright (C) 1994 Free Software Foundation +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +# +# Written by Ian Lance Taylor (ian@cygnus.com) +# + +# Make sure that ld can generate ELF shared libraries. +# Note that linking against ELF shared libraries is tested by the +# bootstrap test. + +# This test can only be run if ld generates native executables. +if ![isnative] then {return} + +# This test can only be run on a couple of ELF platforms. +# Square bracket expressions seem to confuse istarget. +if { ![istarget i386-*-sysv4*] \ + && ![istarget i486-*-sysv4*] \ + && ![istarget i586-*-sysv4*] \ + && ![istarget i386-*-unixware] \ + && ![istarget i486-*-unixware] \ + && ![istarget i586-*-unixware] \ + && ![istarget i386-*-elf*] \ + && ![istarget i486-*-elf*] \ + && ![istarget i586-*-elf*] \ + && ![istarget sparc*-*-elf] \ + && ![istarget sparc*-*-solaris2*]} then { + return +} + +# Compile the main program. +if ![ld_compile "$CC $CFLAGS" $srcdir$subdir/main.c tmpdir/main.o] { + return +} + +# The shared library is composed of two files. First compile them +# without using -fpic. That should work on an ELF system, although it +# will be less efficient because the dynamic linker will need to do +# more relocation work. However, note that not using -fpic will cause +# some of the tests to return different results. +if ![ld_compile "$CC $CFLAGS" $srcdir$subdir/sh1.c tmpdir/sh1.o] { + return +} +if ![ld_compile "$CC $CFLAGS" $srcdir$subdir/sh2.c tmpdir/sh2.o] { + return +} + +# Build the shared library. +if ![ld_simple_link $ld tmpdir/shnonpic.so {-shared tmpdir/sh1.o tmpdir/sh2.o}] { + fail "shared (non PIC)" +} else { + # Link against the shared library. Use -rpath so that the dynamic + # linker can locate the shared library at runtime. + if ![ld_link $ld tmpdir/shnonpic {-rpath tmpdir tmpdir/main.o tmpdir/shnonpic.so}] { + fail "shared (non PIC)" + } else { + # Run the resulting program + send_log "tmpdir/shnonpic >tmpdir/shnonpic.out\n" + verbose "tmpdir/shnonpic >tmpdir/shnonpic.out" + catch "exec tmpdir/shnonpic >tmpdir/shnonpic.out" exec_output + if ![string match "" $exec_output] then { + send_log "$exec_output\n" + verbose "$exec_output" + fail "shared (non PIC)" + } else { + send_log "diff tmpdir/shnonpic.out $srcdir$subdir/shared.dat\n" + verbose "diff tmpdir/shnonpic.out $srcdir$subdir/shared.dat" + catch "exec diff tmpdir/shnonpic.out $srcdir$subdir/shared.dat" exec_output + if [string match "" $exec_output] then { + pass "shared (non PIC)" + } else { + send_log "$exec_output\n" + verbose "$exec_output" + fail "shared (non PIC)" + } + } + } +} + +# Now compile the code using -fpic. Unfortunately, the gcc argument +# is -fpic and the cc argument is -KPIC. We have to try both. + +set picflag "-fpic" +send_log "$CC $picflag\n" +verbose "$CC $picflag" +catch "exec $CC $picflag" exec_output +send_log "$exec_output\n" +verbose "--" "$exec_output" +if { [string match "*illegal option*" $exec_output] \ + || [string match "*option ignored*" $exec_output] \ + || [string match "*unrecognized option*" $exec_output] } then { + set picflag "-KPIC" +} +verbose "Using $picflag to compile PIC code" + +if ![ld_compile "$CC $CFLAGS $picflag" $srcdir$subdir/sh1.c tmpdir/sh1.o] { + return +} +if ![ld_compile "$CC $CFLAGS $picflag" $srcdir$subdir/sh2.c tmpdir/sh2.o] { + return +} + +# Build the shared library. +if ![ld_simple_link $ld tmpdir/shpic.so {-shared tmpdir/sh1.o tmpdir/sh2.o}] { + fail "shared" +} else { + # Link against the shared library. Use -rpath so that the dynamic + # linker can locate the shared library at runtime. + if ![ld_link $ld tmpdir/shpic {-rpath tmpdir tmpdir/main.o tmpdir/shpic.so}] { + fail "shared" + } else { + # Run the resulting program + send_log "tmpdir/shpic >tmpdir/shpic.out\n" + verbose "tmpdir/shpic >tmpdir/shpic.out" + catch "exec tmpdir/shpic >tmpdir/shpic.out" exec_output + if ![string match "" $exec_output] then { + send_log "$exec_output\n" + verbose "$exec_output" + fail "shared" + } else { + send_log "diff tmpdir/shpic.out $srcdir$subdir/shared.dat\n" + verbose "diff tmpdir/shpic.out $srcdir$subdir/shared.dat" + catch "exec diff tmpdir/shpic.out $srcdir$subdir/shared.dat" exec_output + if [string match "" $exec_output] then { + pass "shared" + } else { + send_log "$exec_output\n" + verbose "$exec_output" + fail "shared" + } + } + } +}