2

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

  • You may want to take a look at this presentation [link](https://www.share.org/p/do/sd/topic=788&sid=17084) recently given at SHARE in Pittsburgh; you might recognize the presenter . In it there is a link to a cloud folder with an example of how the author deals with the SMF exit IEFACTRT not only having R1 point to a structure, but R0 having a value as well. (The link is having issues, I'll add a comment.) – zarchasmpgmr Sep 26 '19 at 20:45
  • The [link](https://1drv.ms/f/s!AqpNajCVhlfTg-V_AIVlzc-_PSknCQ) in the presentation is working. Note that there are still some bugs in the program that I have not had time to fix. – zarchasmpgmr Sep 26 '19 at 21:25
  • Ray - you've solved the reverse problem, what if _my_ program is called with non-standard linkage. I'm trying to solve the problem of my program calling _somebody else's_ program that is expecting a non-standard linkage. – Scott Fagen Sep 28 '19 at 19:29
  • Further, to solve the "my external input is not in a standard format," I might solve that problem by writing my own entry prolog (and epilog if my response is non-standard). I might do something like put all of the input(s) into various DSAUSER fields and then have an __asm at the beginning of the main that sets up a pointer to them, mapped as a struct. But I'm sure there are a dozen other ways... :-) – Scott Fagen Sep 28 '19 at 19:41
  • Ah. I understand now. Other than going into __asm and making the call directly…yeah, not easy. I'm guessing this is not an IBM service. Rocket has released (or will be releasing?) some Metal C APIs for system macros into the Zowe project. – zarchasmpgmr Oct 01 '19 at 22:21

1 Answers1

0

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