Mainframe Assembler Migration
DMS® can be used to convert assembler code to modern languages, removing machine artifacts, and producing well-structured maintainable code.
With DMS, the following migrations can be accomplished:
- HLASM -> (IBM) Metal C
- HLASM -> C++
- HLASM -> (IBM Enterprise) COBOL
- HLASM -> Java
- HLASM -> C#
Mainframe Assembler has powered applications for over 50 years, but a shrinking talent pool to manage these systems, and the expensive support cost of the underlying mainframe, has forced many organizations to attempt to convert their legacy Assembler functionality to a more modern programing language. These attempts have typically tried 2 different approaches: Use smart programmers to recode the assembler functionality in the new target language or outsourcing to vendors with automated tools to convert the code.
Recoding efforts have been notoriously unsuccessful. This approach is expensive and error prone; nearly 60% of manual recoding projects fail. At best they suffer from severely extended project timeframes and costs.
Automated code conversion tools, especially for Assembler, are few and hard to find, but have lowered the cost and risk associated with these projects. They often produce code in the new target system that is difficult to maintain. Most such tools convert code blindly line-by-line with virtually no understanding of how the context of the code should shape its translation. Such translators preserve the properties of the original Assembler sometimes to the point of even preserving the syntax and register names from the original code. The translated code may work, but if it is not maintainable the post-migration ongoing support cost can be substantial! (You can see the results of weak translator, not from SD, to compare to the results you see on this page).
The Semantic Designs' DMS translation engine parses the Assembler source code and analyzes like a true compiler, much more deeply than IBM's assembler does; see our HLASM front end). The translator then uses its deep understanding, guided by our translation engineers, to produce smart translations based on customer specific goals for code structure and quality. For example, the translator knows/infers the types of variables, where and how they are used in context. The resulting translation can leverage this knowledge to produce a good result.
A DMS-based HLASM program translation
Here we show you a small sample of HLASM translated by SD's tools to C
A simple HLASM program
We have chosen to provide a small HLASM program (taken from the IBM site) to prevent the reader from being overwhelmed with an 8000 line example.
ASSEM123 CSECT
STM R14,R12,12(R13) SAVE REGS
BALR R12,0 ESTABLISH BASE REGISTER
USING *,R12
ST R13,WKAREA+4
LA R13,WKAREA
SPACE 3
L R6,0(R1) ESTABLISH ADDR TO BEG OF W-S
USING WSSTRT,R6
L R5,4(R1) ESTABLISH ADDR TO END OF W-S
USING WSEND,R5
L R8,8(R1) ESTABLISH ADDR TO W-S SAVE AREA
USING WSSAVE,R8
L R4,12(R1) ESTABLISH ADDR TO W-S PARM LIST
USING WSPARM,R4
MVI DONEFLG,NOTDONE SET FLAG TO NOT DONE
LR R7,R5 PREPARE FOR SUBTRACTION
SR R7,R6 DETERMINE LENGTH OF W-S
AH R7,ONE FOR CORRECT LENGTH, SET UP 1
CH R7,FULLREC BIGGER THAN THE 1K SAVE REC
BH MRECS NEED TO STORE MULTIPLE SAVE RECS
LR R9,R7 SET UP FOR 1 MOVE AND SAVE
STH R7,0(R8) SET LENGTH IN SAVE REC
LA R8,2(R8) BUMP TGT PTR PAST LENGTH 1/2WORD
MVCL R8,R6 MOVE WS TO WS SAVE REC
MVI DONEFLG,DONE SET FLAG TO DONE
B FINISH EXIT
MRECS DS 0H
CLC SAVER6,=F'00' FIRST TIME THROUGH?
BE FIRST R6 OK AS IS, MUST MOVE MAX LRECL
L R6,SAVER6 LOAD PTR TO NEXT WS AREA TO MOVE
LR R7,R5 R5 POINTS TO WS END, CALC
SR R7,R6 DETERMINE LENGTH OF WS TO MOVE
AH R7,ONE SET UP 1 FOR PROPER LENGTH
CH R7,FULLREC REMAINING WS <= SAVE REC SIZE?
BNH CONT1 YES...MOVE ACTUAL WS LENGTH
FIRST LH R7,FULLREC NO...LOAD MAX REC SIZE
CONT1 LR R9,R7 LOAD ODD RECS WIH MOVE LENGTH
STH R7,0(R8) SET LENGTH IN SAVE REC
LA R8,2(R8) BUMP TGT PTR PAST LENGTH
MVCL R8,R6 MOVE WS TO WS SAVE REC
AR R6,R7 BUMP SOURCE PTR BY MOVE LENGTH
ST R6,SAVER6 SAVE FOR NEXT CALL
CR R6,R5 MOVED ALL WS?
BL FINISH NOT YET...EXIT
MVI DONEFLG,DONE SET FLAGE TO DONE
B FINISH AND EXIT
EJECT
FINISH DS 0H
XR R15,R15 ZERO TO RETURN CODE REG
L R13,WKAREA+4 RESTORE BACK PTR
LM R14,R12,12(R13) RESTORE REGS
BR R14 RETURN TO CALLER
SPACE 3
//Defining all the variables used in the assembler routine
WKAREA DS 18F REG SAVE AREA
FULLREC DC H'0998' MAX REX SIZE FOR WS SAVE REC
ONE DC H'0001' MAX REX SIZE FOR WS SAVE REC
SPACE 1
NEWSLEN DC F'00000000' NEW WS LENGTH SAVE AREA
WSACUM DC F'00000000' OLD WS ACCUMULATOR ON RESTORE
WTOMSG WTO 'U0001-** RSAM ABEND - CHANGE IN WORKING STORAGE SIZE',X
ROUTCDE=11,MF=L
SPACE 1
//Here 4 DSECTS are given that correspond to 4 parameters
//sent to the corresponding COBOL code
//(these are captured in the LINKAGE SECTION of the COBOL code)
WSSTRT DSECT WORKING-STORAGE START ADDR
DS F
WSEND DSECT WORKING-STORAGE END ADDR
DS F
WSSAVE DSECT WORKING-STORAGE SAVE RECORD
DS F
WSPARM DSECT WORKING-STORAGE SAVE MODE
MODE DS CL1
SAVER6 DS F R6 SAVE AREA
DONEFLG DS CL1 TELLS IF ALL OF WS WAS MOVED
DONE EQU C'D' DONE MOVE
NOTDONE EQU C'N' NOT DONE MOVE
ERROR EQU C'E' WS LENGTH HAS CHANGED ON RESTART
SPACE 1
R1 EQU 1 PARAMETER LIST ADDRESS
R3 EQU 3 WORK REGISTER
R4 EQU 4 PARAMETER LIST ADDRESS
R5 EQU 5 PARAMETER LIST ADDRESS
R6 EQU 6 W-S PARM ADDR
R7 EQU 7 W-S START ADDR
R8 EQU 8 W-S END ADDR
R9 EQU 9 W-S SAVE RECORD ADDR
R10 EQU 10 SAVE REG FOR W-S START ADDR
R11 EQU 11
R12 EQU 12 MODULE BASE REG
R13 EQU 13
R14 EQU 14 LINK REGISTER
R15 EQU 15 BRANCH REGISTER
SPACE 3
END
HLASM program automatically translated to C
Here we present the translation of the simple HLASM program above to C, below.
One should note that the translator has chosen data types compatible with their declaration in the original program, but with a different representation better suited for C. Note the different choice of C integer types based on the sizes of the values being stored.
It is a fact that assembler programs are essentially the most GOTO-loaded compared to virtually any other program; they largely consist of sequences of LOAD/COMPARE/CONDITIONALGOTO. The DMS-translated code is completely structured; all the spaghetti-tangled code blocks have been organized into a completely structured program without GOTOs. Among the many code cleanups accomplished by DMS, removing the GOTO rat's nests significantly improves the code maintainability.
This output is reproduced exactly as the translator generated it. The translator produces nicely formatted code as a standard by-product.
const char Done = 'D'; // done move
const char Notdone = 'N'; // not done move
short Fullrec = 998; // max rex size for ws save rec
short One = 1; // max rex size for ws save rec
struct Wsparm
{
char Mode;
int Saver6; // r6 save area
char Doneflg; // tells if all of ws was moved
};
/* generic C library */
typedef unsigned int size_t;
int memset(void *p, int v, size_t n)
{
char *c = (char *) p;
for (int i = 0; i < n; i++)
c[i] = v;
}
void *memcpy(void *p1, const void *p2, size_t n)
{
char *c1 = (char *) p1;
char *c2 = (char *) p2;
for (int i = 0; i < n; i++)
c1[i] = c2[i];
}
typedef unsigned int size_t;
int memset(void *p, int v, size_t n);
void fnMain(char *_parms1, char *_parms2, signed short int *_parms3, struct Wsparm *_parms4)
{
char *pc;
signed long int i;
pc = _parms1; // establish addr to beg of w-s
_parms4->Doneflg = Notdone; // establish addr to w-s parm list // set flag to not done
i = _parms2 - pc + One; // establish addr to end of w-s // prepare for subtraction // determine length of w-s // for correct length, set up 1
if (i <= Fullrec) { // bigger than the 1k save rec
*_parms3 = i; // establish addr to w-s save area // set length in save rec
memcpy((char *)(_parms3 + 1), pc, (int)(i & 0x0fff)); // establish addr to w-s save area // set up for 1 move and save // bump tgt ptr past length 1/2word // move ws to ws save rec
_parms4->Doneflg = Done; // establish addr to w-s parm list // set flag to done
return;
}
// label: mrecs
if (_parms4->Saver6 != 0) { // establish addr to w-s parm list // first time through?
pc = *(char **) &_parms4->Saver6; // establish addr to w-s parm list // load ptr to next ws area to move
i = _parms2 - pc + One; // establish addr to end of w-s // r5 points to ws end, calc // determine length of ws to move // set up 1 for proper length
if (i > Fullrec) { // remaining ws <= save rec size?
// label: first
i = Fullrec; // no...load max rec size
}
} else {
// label: first
i = Fullrec; // no...load max rec size
}
// label: cont1
*_parms3 = i; // establish addr to w-s save area // set length in save rec
memcpy((char *)(_parms3 + 1), pc, (int)(i & 0x0fff)); // establish addr to w-s save area // load odd recs wih move length // bump tgt ptr past length // move ws to ws save rec
pc += i; // bump source ptr by move length
_parms4->Saver6 = (signed int) pc; // establish addr to w-s parm list // save for next call
if (pc >= _parms2) { // establish addr to end of w-s // moved all ws?
_parms4->Doneflg = Done; // establish addr to w-s parm list // set flage to done
}
return;
}
One can get good code from a translator, if one has the right foundation technology such as SD's DMS Software Reengineering Toolkit®. As a practical matter, you can't get good code from an off the shelf translator, because every application system has unique properties: languages, OS features, scripting languages, screens, databases, and for assembler, all kinds of custom macros, and a correspondingly unique target as decided by the client. So it takes some effort to configure DMS for the client's particular source and target software configurations.
Configuring a custom migration tool to match client needs
Semantic Designs can provide custom configuration of migration tools and migration support to your organization, providing high quality, maintainable code translations.