| # Expect script for ld-empic tests |
| # Copyright (C) 1994,1995, 1996, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| # |
| # Written by Ian Lance Taylor (ian@cygnus.com) |
| # |
| |
| # Test the handling of MIPS embedded PIC code. This test essentially |
| # tests the compiler and assembler as well as the linker, since MIPS |
| # embedded PIC is a GNU enhancement to standard MIPS tools. |
| |
| # Embedded PIC is only supported for MIPS ECOFF targets. |
| if ![istarget mips*-*-ecoff*] { |
| return |
| } |
| |
| set testname relax |
| |
| if { [which $CC] == 0 } { |
| untested $testname |
| return |
| } |
| |
| # Test that relaxation works correctly. This testsuite was composed |
| # (by experimentation) to force the linker to relax twice--that is, |
| # the first relaxation pass will force another call to be out of |
| # range, requiring a second relaxation pass. |
| if { ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/relax1.c tmpdir/relax1.o] |
| || ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/relax2.c tmpdir/relax2.o] |
| || ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/relax3.c tmpdir/relax3.o] |
| || ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/relax4.c tmpdir/relax4.o] } { |
| unresolved $testname |
| return |
| } |
| |
| if ![ld_simple_link $ld tmpdir/relax "--relax -T $srcdir/$subdir/relax.t tmpdir/relax1.o tmpdir/relax2.o tmpdir/relax3.o tmpdir/relax4.o"] { |
| fail $testname |
| } else { |
| # Check that the relaxation produced the correct result. Check |
| # each bal instruction. Some will go directly to the start of a |
| # function, which is OK. Some will form part of the five |
| # instruction expanded call sequence, in which case we compute the |
| # real destination and make sure it is the start of a function. |
| # Some bal instructions are used to locate the start of the |
| # function in order to do position independent addressing into the |
| # text section, in which case we just check that it correctly |
| # computes the start of the function. |
| |
| # Get the symbol table. |
| if ![ld_nm $nm tmpdir/relax] { |
| unresolved $testname |
| return |
| } |
| |
| # Get a disassembly. |
| send_log "$objdump -d tmpdir/relax >tmpdir/relax.dis\n" |
| verbose "$objdump -d tmpdir/relax >tmpdir/relax.dis" |
| catch "exec $objdump -d tmpdir/relax >tmpdir/relax.dis" exec_output |
| if ![string match "" $exec_output] { |
| send_log "$exec_output\n" |
| verbose $exec_output |
| unresolved $testname |
| return |
| } |
| |
| set balcnt 0 |
| set file [open tmpdir/relax.dis r] |
| while { [gets $file line] != -1 } { |
| verbose "$line" 2 |
| |
| if ![string match "*bal*" $line] { |
| continue |
| } |
| |
| verbose "$line" |
| |
| incr balcnt |
| |
| if ![regexp "^(\[0-9a-fA-F\]+) (<\[a-z+0-9A-Z.\]+>)? bal (\[0-9a-fA-F\]+)" $line whole addr label dest] { |
| perror "unrecognized format for $line" |
| unresolved $testname |
| return |
| } |
| |
| if "0x$addr + 8 != 0x$dest" { |
| # This is a straight function call. All function calls in |
| # this example are to either foo or bar. |
| if "0x$dest != $nm_output(foo) && 0x$dest != $nm_output(bar)" { |
| send_log "fail 1\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| } else { |
| # Pick up the next line. If it is sll, this is a switch |
| # prologue, and there is not much we can do to test it. |
| # Otherwise, it should be lui, and the next instruction |
| # should be an addiu, followed by an addu to $31. |
| if { [gets $file l] == -1 } { |
| send_log "fail 2\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| verbose $l |
| |
| if [string match "*sll*" $l] { |
| continue |
| } |
| if ![regexp "lui (\[\$a-z0-9\]+),(\[0-9a-fA-Fx\]+)" $l whole reg upper] { |
| send_log "fail 3\n" |
| send_log "$line\n" |
| send_log "$l\n" |
| fail $testname |
| return |
| } |
| |
| if { [gets $file l] == -1 } { |
| send_log "fail 4\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| verbose "$l" |
| if ![regexp "addiu \\$reg,\\$reg,(\[-0-9\]+)" $l whole lower] { |
| send_log "fail 5\n" |
| send_log "$line\n" |
| send_log "$l\n" |
| send_log "addiu \\$reg,\\$reg,(\[-0-9\]+)\n" |
| fail $testname |
| return |
| } |
| |
| if { [gets $file l] == -1 } { |
| send_log "fail 6\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| verbose "$l" |
| if ![regexp "addu \\$reg,\\$reg,\\\$ra" $l] { |
| send_log "fail 7\n" |
| send_log "$line\n" |
| send_log "$l\n" |
| fail $testname |
| return |
| } |
| |
| # The next line will be jalr in the case of an expanded |
| # call. Otherwise, the code is getting the start of the |
| # function, and the next line can be anything. |
| |
| if { [gets $file l] == -1 } { |
| send_log "fail 8\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| verbose "$l" |
| if [string match "*jalr*" $l] { |
| set dest [expr 0x$addr + 8 + ($upper << 16) + $lower] |
| if { $dest != $nm_output(foo) && $dest != $nm_output(bar) } { |
| send_log "fail 9\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| } else { |
| set dest [expr ($upper << 16) + $lower] |
| if ![regexp "<(\[.a-z\]+)\\+(\[0-9a-fA-F\]+)>" $label whole base offset] { |
| send_log "fail 10\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| set offset 0x$offset |
| if { $base == ".foo" } { |
| set offset [expr $offset - ($nm_output(foo) - 0x30)] |
| } |
| if { $offset + 8 != - $dest } { |
| send_log "fail 11\n" |
| send_log "$line\n" |
| fail $testname |
| return |
| } |
| } |
| } |
| } |
| |
| close $file |
| |
| if {$balcnt < 10} { |
| send_log "fail 12\n" |
| fail $testname |
| } else { |
| verbose "$balcnt bal instructions" |
| pass $testname |
| } |
| } |
| |
| # We now test actually running embedded MIPS PIC code. This can only |
| # be done on a MIPS host with the same endianness as our target. |
| if [istarget mipsel-*-*] { |
| if ![ishost mips*-*-ultrix*] { |
| return |
| } |
| } else { |
| if ![ishost mips*-*-irix*] { |
| return |
| } |
| } |
| |
| set testname "run embedded PIC code" |
| |
| # Compile the program which will run the test. This code must be |
| # compiled for the host, not the target. |
| send_log "$CC_FOR_HOST $CFLAGS_FOR_HOST -o tmpdir/run $srcdir/$subdir/run.c\n" |
| verbose "$CC_FOR_HOST $CFLAGS_FOR_HOST -o tmpdir/run $srcdir/$subdir/run.c" |
| catch "exec $CC_FOR_HOST $CFLAGS_FOR_HOST -o tmpdir/run $srcdir/$subdir/run.c" exec_output |
| if ![string match "" $exec_output] { |
| send_log "$exec_output\n" |
| verbose "$exec_output" |
| unresolved $testname |
| return |
| } |
| |
| # Compile and link the test. |
| if { ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/runtesti.s tmpdir/runtesti.o] |
| || ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/runtest1.c tmpdir/runtest1.o] |
| || ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir/$subdir/runtest2.c tmpdir/runtest2.o] } { |
| unresolved $testname |
| return |
| } |
| if ![ld_simple_link $ld tmpdir/runtest "--embedded-relocs tmpdir/runtesti.o tmpdir/runtest1.o tmpdir/runtest2.o"] { |
| fail $testname |
| } else { |
| # Now run the test. |
| send_log "tmpdir/run tmpdir/runtest\n" |
| verbose "tmpdir/run tmpdir/runtest" |
| catch "exec tmpdir/run tmpdir/runtest" exec_output |
| if [string match "*ran and returned 0*" $exec_output] { |
| send_log "$exec_output\n" |
| verbose "$exec_output" |
| pass $testname |
| } else { |
| send_log "$exec_output\n" |
| verbose "$exec_output" |
| fail $testname |
| } |
| } |