* 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
11 changed files with 736 additions and 0 deletions
|
@ -28,6 +28,7 @@ config
|
|||
lib
|
||||
ld-bootstrap
|
||||
ld-cdtest
|
||||
ld-empic
|
||||
ld-scripts
|
||||
ld-shared
|
||||
|
||||
|
|
242
ld/testsuite/ld-empic/empic.exp
Normal file
242
ld/testsuite/ld-empic/empic.exp
Normal file
|
@ -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"
|
||||
}
|
||||
}
|
49
ld/testsuite/ld-empic/relax.t
Normal file
49
ld/testsuite/ld-empic/relax.t
Normal file
|
@ -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 = .;
|
||||
}
|
22
ld/testsuite/ld-empic/relax1.c
Normal file
22
ld/testsuite/ld-empic/relax1.c
Normal file
|
@ -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 () { }
|
19
ld/testsuite/ld-empic/relax2.c
Normal file
19
ld/testsuite/ld-empic/relax2.c
Normal file
|
@ -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 ();
|
||||
}
|
3
ld/testsuite/ld-empic/relax3.c
Normal file
3
ld/testsuite/ld-empic/relax3.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* Third source file in relaxation test. */
|
||||
|
||||
int quux () { return 0; }
|
3
ld/testsuite/ld-empic/relax4.c
Normal file
3
ld/testsuite/ld-empic/relax4.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* Fourth source file in relaxation test. */
|
||||
|
||||
int xyzzy () { return 0; }
|
160
ld/testsuite/ld-empic/run.c
Normal file
160
ld/testsuite/ld-empic/run.c
Normal file
|
@ -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);
|
||||
}
|
117
ld/testsuite/ld-empic/runtest1.c
Normal file
117
ld/testsuite/ld-empic/runtest1.c
Normal file
|
@ -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;
|
||||
}
|
26
ld/testsuite/ld-empic/runtest2.c
Normal file
26
ld/testsuite/ld-empic/runtest2.c
Normal file
|
@ -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;
|
||||
}
|
94
ld/testsuite/ld-empic/runtesti.s
Normal file
94
ld/testsuite/ld-empic/runtesti.s
Normal file
|
@ -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…
Add table
Reference in a new issue