* config/default.exp: Define objdump if it is not defined.
* ld-empic/*: New tests to test -membedded-pic code.
This commit is contained in:
parent
dc5df17b8a
commit
3c2476067c
|
@ -28,6 +28,7 @@ config
|
||||||
lib
|
lib
|
||||||
ld-bootstrap
|
ld-bootstrap
|
||||||
ld-cdtest
|
ld-cdtest
|
||||||
|
ld-empic
|
||||||
ld-scripts
|
ld-scripts
|
||||||
ld-shared
|
ld-shared
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,242 @@
|
||||||
|
# Expect script for ld-empic 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)
|
||||||
|
#
|
||||||
|
|
||||||
|
# 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 }
|
||||||
|
|
||||||
|
# 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] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir$subdir/relax2.c tmpdir/relax2.o] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir$subdir/relax3.c tmpdir/relax3.o] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir$subdir/relax4.c tmpdir/relax4.o] {
|
||||||
|
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 relax
|
||||||
|
} 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] {
|
||||||
|
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
|
||||||
|
perror "tmpdir/relax: objdump failed"
|
||||||
|
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"
|
||||||
|
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 "$line\n"
|
||||||
|
fail "relax (bad direct function call)"
|
||||||
|
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 "$line\n"
|
||||||
|
fail "relax (unexpected EOF after bal)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verbose $l
|
||||||
|
|
||||||
|
if [string match "*sll*" $l] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ![regexp "lui (\[\$a-z0-9\]+),(\[0-9\]+)" $l whole reg upper] {
|
||||||
|
send_log "$line\n"
|
||||||
|
send_log "$l\n"
|
||||||
|
fail "relax (could not find expected lui)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [gets $file l] == -1 } {
|
||||||
|
send_log "$line\n"
|
||||||
|
fail "relax (unexpected EOF after lui)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verbose "$l"
|
||||||
|
if ![regexp "addiu \\$reg,\\$reg,(\[-0-9\]+)" $l whole lower] {
|
||||||
|
send_log "$line\n"
|
||||||
|
send_log "$l\n"
|
||||||
|
send_log "addiu \\$reg,\\$reg,(\[-0-9\]+)\n"
|
||||||
|
fail "relax (could not find expected addiu)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [gets $file l] == -1 } {
|
||||||
|
send_log "$line\n"
|
||||||
|
fail "relax (unexpected EOF after addiu)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verbose "$l"
|
||||||
|
if ![regexp "addu \\$reg,\\$reg,\\\$ra" $l] {
|
||||||
|
send_log "$line\n"
|
||||||
|
send_log "$l\n"
|
||||||
|
fail "relax (could not find expected addu)"
|
||||||
|
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 "$line\n"
|
||||||
|
fail "relax (unexpected EOF after addu)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "$line\n"
|
||||||
|
fail "relax (bad expanded function call)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set dest [expr ($upper << 16) + $lower]
|
||||||
|
if ![regexp "<\[a-z\]+\\+(\[0-9a-fA-F\]+)>" $label whole offset] {
|
||||||
|
send_log "$line\n"
|
||||||
|
fail "relax (unrecognized label)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if "0x$offset + 8 != - $dest" {
|
||||||
|
send_log "$line\n"
|
||||||
|
fail "relax (bad function start: 0x$offset + 8 != - $dest)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close $file
|
||||||
|
|
||||||
|
if {$balcnt < 10} {
|
||||||
|
fail "relax (not enough branches)"
|
||||||
|
} else {
|
||||||
|
verbose "$balcnt bal instructions"
|
||||||
|
pass relax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
perror "$srcdir$subdir/run.c: compilation failed"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compile and link the test.
|
||||||
|
if ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir$subdir/runtesti.s tmpdir/runtesti.o] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir$subdir/runtest1.c tmpdir/runtest1.o] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC $CFLAGS -membedded-pic" $srcdir$subdir/runtest2.c tmpdir/runtest2.o] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ![ld_simple_link $ld tmpdir/runtest "--embedded-relocs tmpdir/runtesti.o tmpdir/runtest1.o tmpdir/runtest2.o"] {
|
||||||
|
fail "run embedded PIC code (link)"
|
||||||
|
} 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 "run embedded PIC code"
|
||||||
|
} else {
|
||||||
|
send_log "$exec_output\n"
|
||||||
|
verbose "$exec_output"
|
||||||
|
fail "run embedded PIC code"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
OUTPUT_FORMAT("ecoff-bigmips")
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.foo 0x30 : {
|
||||||
|
tmpdir/relax3.o(.text)
|
||||||
|
tmpdir/relax1.o(.text)
|
||||||
|
}
|
||||||
|
.text 0x20000 : {
|
||||||
|
_ftext = . ;
|
||||||
|
*(.init)
|
||||||
|
eprol = .;
|
||||||
|
tmpdir/relax4.o(.text)
|
||||||
|
*(.text)
|
||||||
|
*(.fini)
|
||||||
|
etext = .;
|
||||||
|
_etext = .;
|
||||||
|
}
|
||||||
|
.rdata . : {
|
||||||
|
*(.rdata)
|
||||||
|
}
|
||||||
|
_fdata = .;
|
||||||
|
.data . : {
|
||||||
|
*(.data)
|
||||||
|
CONSTRUCTORS
|
||||||
|
}
|
||||||
|
_gp = . + 0x8000;
|
||||||
|
.lit8 . : {
|
||||||
|
*(.lit8)
|
||||||
|
}
|
||||||
|
.lit4 . : {
|
||||||
|
*(.lit4)
|
||||||
|
}
|
||||||
|
.sdata . : {
|
||||||
|
*(.sdata)
|
||||||
|
}
|
||||||
|
edata = .;
|
||||||
|
_edata = .;
|
||||||
|
_fbss = .;
|
||||||
|
.sbss . : {
|
||||||
|
*(.sbss)
|
||||||
|
*(.scommon)
|
||||||
|
}
|
||||||
|
.bss . : {
|
||||||
|
*(.bss)
|
||||||
|
*(COMMON)
|
||||||
|
}
|
||||||
|
end = .;
|
||||||
|
_end = .;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* First source file in relaxation test. */
|
||||||
|
|
||||||
|
extern int bar ();
|
||||||
|
static int foo2 ();
|
||||||
|
|
||||||
|
int foo (int i)
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0: bar (0); break;
|
||||||
|
case 1: bar (1); break;
|
||||||
|
case 2: bar (2); break;
|
||||||
|
case 3: bar (3); break;
|
||||||
|
case 4: bar (foo2); break;
|
||||||
|
case 5: bar (bar); break;
|
||||||
|
}
|
||||||
|
while (1)
|
||||||
|
if (i)
|
||||||
|
return bar ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int foo2 () { }
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* Second source file in relaxation test. */
|
||||||
|
|
||||||
|
int bar2 ()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
foo ();
|
||||||
|
return foo () + foo () + foo () + foo ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int bar (int i)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
if (i)
|
||||||
|
return foo ();
|
||||||
|
else
|
||||||
|
return foo ();
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* Third source file in relaxation test. */
|
||||||
|
|
||||||
|
int quux () { return 0; }
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* Fourth source file in relaxation test. */
|
||||||
|
|
||||||
|
int xyzzy () { return 0; }
|
|
@ -0,0 +1,160 @@
|
||||||
|
/* Load and run a MIPS position independent ECOFF file.
|
||||||
|
Written by Ian Lance Taylor <ian@cygnus.com>
|
||||||
|
Public domain. */
|
||||||
|
|
||||||
|
/* This program will load an ECOFF file into memory and execute it.
|
||||||
|
The file must have been compiled using the GNU -membedded-pic
|
||||||
|
switch to produce position independent code. This will only work
|
||||||
|
if this program is run on a MIPS system with the same endianness as
|
||||||
|
the ECOFF file. The ECOFF file must be complete. System calls may
|
||||||
|
not work correctly.
|
||||||
|
|
||||||
|
There are further restrictions on the file (they could be removed
|
||||||
|
by doing some additional programming). The file must be aligned
|
||||||
|
such that it does not require any gaps introduced in the data
|
||||||
|
segment; the GNU linker produces such files by default. However,
|
||||||
|
the file must not assume that the text or data segment is aligned
|
||||||
|
on a page boundary. The start address must be at the start of the
|
||||||
|
text segment.
|
||||||
|
|
||||||
|
The ECOFF file is run by calling it as though it were a function.
|
||||||
|
The address of the data segment is passed as the only argument.
|
||||||
|
The file is expected to return an integer value, which will be
|
||||||
|
printed. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/* Structures used in ECOFF files. We assume that a short is two
|
||||||
|
bytes and an int is four bytes. This is not much of an assumption,
|
||||||
|
since we already assume that we are running on a MIPS host with the
|
||||||
|
same endianness as the file we are examining. */
|
||||||
|
|
||||||
|
struct ecoff_filehdr {
|
||||||
|
unsigned short f_magic; /* magic number */
|
||||||
|
unsigned short f_nscns; /* number of sections */
|
||||||
|
unsigned int f_timdat; /* time & date stamp */
|
||||||
|
unsigned int f_symptr; /* file pointer to symtab */
|
||||||
|
unsigned int f_nsyms; /* number of symtab entries */
|
||||||
|
unsigned short f_opthdr; /* sizeof(optional hdr) */
|
||||||
|
unsigned short f_flags; /* flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ecoff_aouthdr
|
||||||
|
{
|
||||||
|
unsigned short magic; /* type of file */
|
||||||
|
unsigned short vstamp; /* version stamp */
|
||||||
|
unsigned int tsize; /* text size in bytes, padded to FW bdry*/
|
||||||
|
unsigned int dsize; /* initialized data " " */
|
||||||
|
unsigned int bsize; /* uninitialized data " " */
|
||||||
|
unsigned int entry; /* entry pt. */
|
||||||
|
unsigned int text_start; /* base of text used for this file */
|
||||||
|
unsigned int data_start; /* base of data used for this file */
|
||||||
|
unsigned int bss_start; /* base of bss used for this file */
|
||||||
|
unsigned int gprmask; /* ?? */
|
||||||
|
unsigned int cprmask[4]; /* ?? */
|
||||||
|
unsigned int gp_value; /* value for gp register */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ECOFF_SCNHDR_SIZE (40)
|
||||||
|
|
||||||
|
static void
|
||||||
|
die (s)
|
||||||
|
char *s;
|
||||||
|
{
|
||||||
|
perror (s);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
struct stat s;
|
||||||
|
char *z;
|
||||||
|
struct ecoff_filehdr *fh;
|
||||||
|
struct ecoff_aouthdr *ah;
|
||||||
|
unsigned int toff;
|
||||||
|
char *t, *d;
|
||||||
|
int (*pfn) ();
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Usage: %s file\n", argv[0]);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen (argv[1], "r");
|
||||||
|
if (f == NULL)
|
||||||
|
die (argv[1]);
|
||||||
|
|
||||||
|
if (stat (argv[1], &s) < 0)
|
||||||
|
die ("stat");
|
||||||
|
|
||||||
|
z = (char *) malloc (s.st_size);
|
||||||
|
if (z == NULL)
|
||||||
|
die ("malloc");
|
||||||
|
|
||||||
|
if (fread (z, 1, s.st_size, f) != s.st_size)
|
||||||
|
die ("fread");
|
||||||
|
|
||||||
|
/* We need to figure out the start of the text segment, which is the
|
||||||
|
location we are going to call, and the start of the data segment,
|
||||||
|
which we are going to pass as an argument. We also need the size
|
||||||
|
and start address of the bss segment. This information is all in
|
||||||
|
the ECOFF a.out header. */
|
||||||
|
|
||||||
|
fh = (struct ecoff_filehdr *) z;
|
||||||
|
if (fh->f_opthdr != sizeof (struct ecoff_aouthdr))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s: unexpected opthdr size: is %u, want %u\n",
|
||||||
|
argv[1], (unsigned int) fh->f_opthdr,
|
||||||
|
(unsigned int) sizeof (struct ecoff_aouthdr));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ah = (struct ecoff_aouthdr *) (z + sizeof (struct ecoff_filehdr));
|
||||||
|
if (ah->magic != 0413)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s: bad aouthdr magic number 0%o (want 0413)\n",
|
||||||
|
argv[1], (unsigned int) ah->magic);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should clear the bss segment at this point. This is the
|
||||||
|
ah->bsize bytes starting at ah->bss_start, To do this correctly,
|
||||||
|
we would have to make sure our memory block is large enough. It
|
||||||
|
so happens that our test case does not have any additional pages
|
||||||
|
for the bss segment--it is contained within the data segment.
|
||||||
|
So, we don't bother. */
|
||||||
|
if (ah->bsize != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"%s: bss segment is %u bytes; non-zero sizes not supported\n",
|
||||||
|
argv[1], ah->bsize);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The text section starts just after all the headers, rounded to a
|
||||||
|
16 byte boundary. */
|
||||||
|
toff = (sizeof (struct ecoff_filehdr) + sizeof (struct ecoff_aouthdr)
|
||||||
|
+ fh->f_nscns * ECOFF_SCNHDR_SIZE);
|
||||||
|
toff += 15;
|
||||||
|
toff &=~ 15;
|
||||||
|
t = z + toff;
|
||||||
|
|
||||||
|
/* The tsize field gives us the start of the data segment. */
|
||||||
|
d = z + ah->tsize;
|
||||||
|
|
||||||
|
/* Call the code as a function. */
|
||||||
|
pfn = (int (*) ()) t;
|
||||||
|
ret = (*pfn) (d);
|
||||||
|
|
||||||
|
printf ("%s ran and returned %d\n", argv[1], ret);
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* First C source file for actual execution test. */
|
||||||
|
|
||||||
|
/* The main point of this test is to make sure that the code and data
|
||||||
|
are truly position independent. We statically initialize several
|
||||||
|
global variables, and make sure that they are correctly adjusted at
|
||||||
|
runtime. */
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
int j = 0;
|
||||||
|
extern int k;
|
||||||
|
int l;
|
||||||
|
char small_buf[] = "aaaa";
|
||||||
|
char *small_pointer = small_buf;
|
||||||
|
char big_buf[] = "aaaaaaaaaaaaaaaa";
|
||||||
|
char *big_pointer = big_buf;
|
||||||
|
|
||||||
|
extern int bar ();
|
||||||
|
int (*pbar) () = bar;
|
||||||
|
|
||||||
|
static int
|
||||||
|
foo2 (arg)
|
||||||
|
int arg;
|
||||||
|
{
|
||||||
|
l = arg;
|
||||||
|
return i + j;
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*pfoo2) () = foo2;
|
||||||
|
|
||||||
|
int
|
||||||
|
chkstr (z, c)
|
||||||
|
char *z;
|
||||||
|
int c;
|
||||||
|
{
|
||||||
|
/* Switch statements need extra effort to be position independent,
|
||||||
|
so we run one here, even though most of the cases will never be
|
||||||
|
taken. */
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
return i - 1;
|
||||||
|
case 4:
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
return i * j;
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
case 14:
|
||||||
|
case 15:
|
||||||
|
return j;
|
||||||
|
case 16:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (c-- != 0)
|
||||||
|
if (*z++ != 'a')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return *z == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is called by the assembler startup routine. It tries
|
||||||
|
to test that everything was correctly initialized. It returns 0 on
|
||||||
|
success, something else on failure. */
|
||||||
|
|
||||||
|
int
|
||||||
|
foo ()
|
||||||
|
{
|
||||||
|
if (i != 1)
|
||||||
|
return 1;
|
||||||
|
if (j != 0)
|
||||||
|
return 2;
|
||||||
|
if (! chkstr (small_buf, 4))
|
||||||
|
return 3;
|
||||||
|
if (! chkstr (small_pointer, 4))
|
||||||
|
return 4;
|
||||||
|
if (! chkstr (big_buf, 16))
|
||||||
|
return 5;
|
||||||
|
if (! chkstr (big_pointer, 16))
|
||||||
|
return 6;
|
||||||
|
|
||||||
|
if (l != 0)
|
||||||
|
return 7;
|
||||||
|
if (foo2 (1) != 1)
|
||||||
|
return 8;
|
||||||
|
if (l != 1)
|
||||||
|
return 9;
|
||||||
|
if ((*pfoo2) (2) != 1)
|
||||||
|
return 10;
|
||||||
|
if (l != 2)
|
||||||
|
return 11;
|
||||||
|
|
||||||
|
if (bar (1) != 0)
|
||||||
|
return 12;
|
||||||
|
if (bar (-1) != 1)
|
||||||
|
return 13;
|
||||||
|
if ((*pbar) (0xa5a5a5a5) != -1)
|
||||||
|
return 14;
|
||||||
|
if (k != 0xa5a5a5a5)
|
||||||
|
return 15;
|
||||||
|
if ((*pbar) (0) != 0xa5a5a5a5)
|
||||||
|
return 16;
|
||||||
|
if (k != 0)
|
||||||
|
return 17;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Second C source file for actual execution test. */
|
||||||
|
|
||||||
|
int k;
|
||||||
|
extern int i;
|
||||||
|
extern int j;
|
||||||
|
extern char small_buf[];
|
||||||
|
extern char *small_pointer;
|
||||||
|
|
||||||
|
extern int chkstr ();
|
||||||
|
|
||||||
|
int
|
||||||
|
bar (n)
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (i != 1
|
||||||
|
|| j != 0
|
||||||
|
|| ! chkstr (small_buf, 4)
|
||||||
|
|| ! chkstr (small_pointer, 4))
|
||||||
|
return k + 1;
|
||||||
|
|
||||||
|
r = k;
|
||||||
|
k = n;
|
||||||
|
return r;
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
# Assembler initialization code for actual execution test.
|
||||||
|
|
||||||
|
# This code becomes the start of the execution test program. It is
|
||||||
|
# responsible for initializing the static data, invoking the C code,
|
||||||
|
# and returning the result. It is called as though it were a C
|
||||||
|
# function with an argument of the address of the data segment.
|
||||||
|
|
||||||
|
# We need to know the value of _ftext and _fdata at link time, but we
|
||||||
|
# have no way to actually get that at runtime. This is because when
|
||||||
|
# this code is compiled with -membedded-pic, the la instruction will
|
||||||
|
# be turned into an addiu $gp instruction. We work around this by
|
||||||
|
# storing the information in words in the .data section. We then load
|
||||||
|
# the values of these words *before* doing the runtime relocation.
|
||||||
|
.sdata
|
||||||
|
text_start:
|
||||||
|
.word _ftext
|
||||||
|
data_start:
|
||||||
|
.word _fdata
|
||||||
|
|
||||||
|
.globl start
|
||||||
|
.text
|
||||||
|
start:
|
||||||
|
# Grab some space on the stack, just as though we were a real
|
||||||
|
# function.
|
||||||
|
addiu $sp,$sp,-8
|
||||||
|
sw $31,0($sp)
|
||||||
|
|
||||||
|
# Save the $gp register, and set it up for our data section.
|
||||||
|
sw $gp,4($sp)
|
||||||
|
|
||||||
|
addu $gp,$4,0x8000 # macro
|
||||||
|
|
||||||
|
# The start of the data segment is in $4.
|
||||||
|
|
||||||
|
# Get the address of start into $5 in a position independent
|
||||||
|
# fashion.
|
||||||
|
.set noreorder
|
||||||
|
$LF1 = . + 8
|
||||||
|
bal $LF1
|
||||||
|
la $5,start-$LF1 # macro
|
||||||
|
.set reorder
|
||||||
|
addu $5,$5,$31
|
||||||
|
|
||||||
|
# Now get the address of _ftext into $6.
|
||||||
|
la $6,_ftext-start # macro
|
||||||
|
addu $6,$6,$5
|
||||||
|
|
||||||
|
# Get the value of _ftext used to link into $7.
|
||||||
|
lw $7,text_start # macro
|
||||||
|
|
||||||
|
# Get the value of _fdata used to link into $8.
|
||||||
|
lw $8,data_start # macro
|
||||||
|
|
||||||
|
# Get the address of __runtime_reloc_start into $9.
|
||||||
|
la $9,__runtime_reloc_start-start # macro
|
||||||
|
addu $9,$9,$5
|
||||||
|
|
||||||
|
# Get the address of __runtime_reloc_stop into $10.
|
||||||
|
la $10,__runtime_reloc_stop-start # macro
|
||||||
|
addu $10,$10,$5
|
||||||
|
|
||||||
|
# The words between $9 and $10 are the runtime initialization
|
||||||
|
# instructions. Step through and relocate them. First set
|
||||||
|
# $11 and $12 to the values to add to text and data sections,
|
||||||
|
# respectively.
|
||||||
|
subu $11,$6,$7
|
||||||
|
subu $12,$4,$8
|
||||||
|
|
||||||
|
1:
|
||||||
|
bge $9,$10,3f # macro
|
||||||
|
lw $13,0($9)
|
||||||
|
and $14,$13,0xfffffffe # macro
|
||||||
|
move $15,$11
|
||||||
|
beq $13,$14,2f
|
||||||
|
move $15,$12
|
||||||
|
2:
|
||||||
|
addu $14,$14,$4
|
||||||
|
lw $24,0($14)
|
||||||
|
addu $24,$24,$15
|
||||||
|
sw $24,0($14)
|
||||||
|
addiu $9,$9,4
|
||||||
|
b 1b
|
||||||
|
3:
|
||||||
|
|
||||||
|
# Now the statically initialized data has been relocated
|
||||||
|
# correctly, and we can call the C code which does the actual
|
||||||
|
# testing.
|
||||||
|
bal foo
|
||||||
|
|
||||||
|
# We return the value returned by the C code.
|
||||||
|
lw $31,0($sp)
|
||||||
|
lw $gp,4($sp)
|
||||||
|
addu $sp,$sp,8
|
||||||
|
j $31
|
Loading…
Reference in New Issue