>The programmer in question is a C / UNIX programmer new to the 3K, using
>the gnu c++ compiler. Me, I don't use intrinsics for I/O, so am almost
>useless (but please don't quote me on that). Can someone help us
>understand this behavior?
[snip]
It would be nice to see more of the code around the FOPEN, but I'm
pretty sure it is because you've not declared and initialized the rest
of the parameters. Please note that many intrinsics are declared IN THE
INTRINSICS FILE with default parameters such that if you don't supply
them all, the defaults will automatically be assigned. However, gcc
doesn't look at the intrinsics file, so you have to declare the
parameters and initialize them yourself. What can account for the
randomness of it succeeding and failing is the values left over in your
frame that happen to fall in the correct positions to be intpreted as
parameters to FOPEN.
There are other complications too when calling intrinsics in that some
parameters can be long pointers. I find that Lund's toolkit tool CSEQ
(written by Stan) is almost a requirement if you plan to use intrinsics
with gcc. I also have a file called longpointer.h that helps implement
long pointers with gcc.
I periodically publish the attached goo in support of long pointers, and
I guess this is as good an opportunity.
First, here is a (somewhat messy, but you'll get the idea) chunk of code
I wrote for the Java port. It shows an implementation that should work
with both HP/C and gcc:
#ifdef __GNUC__
extern void HPGETPROCPLABEL( int parms,
void * procname,
void * plabel,
void * status,
void * firstfile,
int casesensitive,
/* following added in 5.5 */ int symbol_type,
void * data_size,
int position,
int search_path,
int binding);
extern void HPFIRSTLIBRARY( int parms,
void * mpename,
void * status,
void * mpelength,
void * firstlib,
void * length,
void * syntax);
extern void HPMYPROGRAM( int parms,
void * mpename,
void * status,
void * mpelength,
void * progname,
void * length,
void * syntax);
#define T_STATUS struct { short subsys; short info; }
#define CALL_HPGETPROCPLABEL(procname, plabel, status, \
firstfile, casesensitive, symbol_type, data_size, \
position, search_path, binding) \
HPGETPROCPLABEL(10, (procname), (plabel), (status), \
(firstfile), (casesensitive), (symbol_type), \
(data_size), (position), (search_path), (binding));
#define CALL_HPFIRSTLIBRARY(mpefile, status, mpelength,\
firstlib, length, syntax) \
HPFIRSTLIBRARY(6, (mpefile), (status), (mpelength), \
(firstlib), (length), (syntax))
#define CALL_HPMYPROGRAM(mpefile, status, mpelength, \
progname, length, syntax) \
HPMYPROGRAM(6, (mpefile), (status), (mpelength), \
(progname), (length), (syntax))
#else
#pragma intrinsic HPGETPROCPLABEL
#pragma intrinsic HPFIRSTLIBRARY
#pragma intrinsic HPMYPROGRAM
#define T_STATUS t_mpe_status
#define CALL_HPGETPROCPLABEL(procname, plabel, status, \
firstfile, casesensitive, symbol_type, data_size, \
position, search_path, binding) \
HPGETPROCPLABEL((procname), (plabel), (status), \
(firstfile), (casesensitive), (symbol_type), \
(data_size), (position), (search_path), (binding));
#define CALL_HPFIRSTLIBRARY(mpefile, status, mpelength, \
firstlib, length, syntax) \
HPFIRSTLIBRARY((mpefile), (status), (mpelength),
(firstlib), (length), (syntax))
#define CALL_HPMYPROGRAM(mpefile, status, mpelength, \
progname, length, syntax) \
HPMYPROGRAM((mpefile), (status), (mpelength), \
(progname), (length), (syntax))
#endif
Note that the intrinsics are not directly called within the code, but
through the CALL_ macros. For the gcc version, I've declared and used
the "hidden" parameters that these intrinsics require.
None of the above examples use long pointers. However, the PRINT
intrinsic does, and here is a simple example of how to do that in gcc:
#include "longpointer.h"
main()
{
char *buf = "this is a test!";
char buf1[80];
int ccode;
extern int CCODE();
extern int errno;
extern void PRINT(LONGPOINTER lp,
short length,
short control);
LONGPOINTER lp_buf = longaddr(buf);
PRINT(lp_buf,-strlen(buf),0);
ccode = CCODE();
sprintf(buf1, "ccode from PRINT call: %d\n",ccode);
PRINT(longaddr(buf1),-strlen(buf1),0);
if (errno != 0)
{
sprintf(buf1, "errno: %d\n", errno);
PRINT(longaddr(buf1),-strlen(buf1),0);
}
};
Finally, here is the goo called "longpointer.h". I hope this little
gcc tutorial was informative.
/tmp(227): cat longpointer.h
typedef struct {
int spaceid;
unsigned int offset;
} LONGPOINTER;
int getspaceid(void *source)
{
/*
* Given the short pointer, determine it's space ID.
*/
asm("comiclr,= 0,%r26,%r28");
asm("ldsid (%r0,%r26),%r28");
};
LONGPOINTER longaddr(void *source) // %r26 == offset
{
/*
* Return the long pointer for the address in sr5 space.
*/
asm("or %r26,%r0,%r29");
asm("comiclr,= 0,%r26,%r28");
asm("ldsid (%r0,%r26),%r28");
};
void longmove(int len, // %r26 == byte length
LONGPOINTER source, // %r23 == source space, %r24 == off
LONGPOINTER target) // sp-#56 == target space, sp-#52== off
{
/*
* Move data between two buffers in long pointer space.
*/
/*
* This goo is to remove data from arg0-arg3 and place it in the frame
* since these registers are needed for the millicode call.
*/
int bytelen = len;
int srcspace = source.spaceid;
int srcoff = source.offset;
int trgspace = target.spaceid;
int trgoff = target.offset;
asm(".import $$lr_unk_unk_long,MILLICODE");
/*
* The colons separate output from input parameters. In this case,
* there are no output references from the instructions. The "m"
* constraint indicates that the following token is a memory reference.
* The general format is:
* asm("<instruction template>" : <output> : <input>);
* where <output> and <input> are:
* "<constraint>" (<token>)
* <instruction template> is the PA-RISC instruction in template fmt.
* Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
*/
asm("ldw %0,%%r1" :: "m" (srcspace)); // load source space to %r1
asm("mtsp %r1,%sr1"); // copy source space to %sr1
asm("ldw %0,%%r26" :: "m" (srcoff)); // load source offset to %r26
asm("ldw %0,%%r24" :: "m" (len)); // load length to %r24
asm("ldw %0,%%r25" :: "m" (trgoff)); // load target offset to %r25
asm("ldw %0,%%r1" :: "m" (trgspace)); // load target space to %r1
asm("bl $$lr_unk_unk_long,%r31"); // start branch to millicode
asm("mtsp %r1,%sr2"); // copy target space to %sr2
};
int longpeek(LONGPOINTER source) // %r25 == spaceid, %r26 == offset
{
/*
* Fetch the int in long pointer space.
*/
asm("mtsp %r25,%sr1");
asm("ldw 0(%sr1,%r26),%r28");
};
void longpoke(LONGPOINTER target, // %r25 == spaceid, %r26 == offset
unsigned int val) // %r24 == value
{
/*
* Store the val into long pointer space.
*/
asm("mtsp %r25,%sr1");
asm("stw %r24, 0(%sr1,%r26)");
};
void move_fast(int len, // %r26 == byte length
void *src, // %r25 == source addr
void *trg) // %r24 == target addr
{
/*
* Move using short pointers.
*/
asm(".import $$lr_unk_unk,MILLICODE");
asm("or %r26,%r0,%r1"); // Copy length to %r1 (temp)
asm("or %r25,%r0,%r26"); // Move source addr into position
asm("or %r24,%r0,%r25"); // Move target addr into position
asm("bl $$lr_unk_unk,%r31"); // Start branch to millicode
asm("or %r1,%r0,%r24"); // Move length into position
};
/tmp(228):
|