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                         
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    
        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                    
        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                                                        

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
    // 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

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.

For more information:    Follow us at Twitter: @SemanticDesigns