Scott Fagen
Scott Fagen

Reputation: 109

Parameter Passing - Non-standard Linkage

I am a long time assembler programmer, moving into the world of Metal C. I am very much a C novice, so my terminology may reflect the stuff that I know vs. the stuff that I am learning. It will certainly color how I understand things.

I am trying to insert new Metal C code into some old components that don't necessarily follow standard entry linkage conventions.

For example, a service routine takes, as input in R1, the address of a control block to process. I've looked at the Metal C User's Guide at the discussion about parameter passing and the #pragma linkage discussion in the language reference and there doesn't seem to be a means to cause the compiler to do this.

In essence, I want to declare a routine that is invoked by the following assembler:

     L R1,MyParm@      Put pointer to Parm into R1
     L R15,Routine@    Get address of service routine
     BASR R14,R15      Branch to service routine

I realize that I can take the above, parameterize it and put it into an __asm() block, but I would like to keep the program as "clean" as possible.

Thanks, Scott

Addendum - 26 September 2019

To respond to Mark Hiscock's answer below, such an __asm() block would look like:

#define CallwithR1(ParmPtr,RoutinePtr,RC,Rsn)                                 \
__asm(                                                                        \
"         L     R1,%2                     Get ParmPtr into R1 \n"             \
"         L     R15,%3                    Get RoutinePtr into R15 \n"         \
"         BALR  R14,R15                   Call the routine \n"                \
"         ST    R15,%0                    Save the return code \n"            \
"         ST    R0,%1                     Save the reason code \n"            \
/* Output variables                                                        */ \
: "=m"(RC)                             /* %0, output only, in-memory       */ \
 ,"=m"(Rsn)                            /* %1, output only, in memory       */ \
/* Input variables                                                         */ \
: "m"(ParmPtr)                         /* %2, input, in-memory             */ \
 ,"m"(RoutinePtr)                      /* %3, input, in-memory             */ \
/* Register clobber list                                                   */ \
: "r0"                                 /* R0 clobbered by reason code      */ \
 ,"r1"                                 /* R1 clobbered by linkage code     */ \
 ,"r14"                                /* R14 clobbered by return addr     */ \
 ,"r15"                                /* R15 clobbered by return code     */ \
);                                                                                                

and would be far simpler to deal with (fewer instructions, no bind time issues). I'm really looking for something that allows the compiler to "do the right thing."

Scott

Upvotes: 2

Views: 158

Answers (1)

Mark Hiscock
Mark Hiscock

Reputation: 1

You could try something like this in the C program:

#pragma linkage(MYHLASM,OS)

And then call the function like this:

MYHLASM(&pointerToParmWhichBecomesR1);

Then the assembler would look like this:

MYHLASM  CSECT ,
MYHLASM  AMODE 64
MYHLASM  RMODE 31
         STG   14,12(13)
         LG    2,0(,1)
         USING *,15
         DO SOMETHING WITH THE PARM ADDR WHICH IS NOW IN R2
         LG    14,12(13)
         BR    14
         LTORG
         END

This is a 64bit example and MYHLASM would have to be available at the bind time of the C program.

Hope this helps,

Mark

Upvotes: 0

Related Questions