REXX Language implementation
A disassembler reverses the actions of an assembler; where the assembler turns a text file containing instructions and directives into a binary executable, the disassembler returns this binary file into its text form1 ;in this case it delivers a disassembly which in itself can be re-assembled - and still works.
The rxdas disassembler has a .rxbin file as input and
produces a text file as output which goes to stdout. In this
text file a disassembly has taken place; labels are synthetic and
based on the combination of instructions around them. As clearly can
be seen in the above, the labels generated by the cRexx compiler
are not the same as the ones generated by the disassembler. With
option -p, the constant pool of the .rxbin file is
printed first, before the rest of the disassembly.
The current 006 .rxbin format is fully supported,
including pooled float literals, packed code and constant sections,
and the interface/class metadata directives
.class, .attr, .interface,.implements, and .member.
Assembler-built jump tables are reconstructed as procedure-local synthetic
.jtable and .jcase declarations. The disassembly records the packed
algorithm actually selected (linear, openhash, or acph) and rewrites
jumps, jumpr, jumpn, jumpb, jumpbs, and jumpi operands to the
synthetic table name. Numeric tables omit the internal NaN compatibility entry,
which is recreated by rxas when the disassembly is assembled again.
When the command line argument -h is specified the options are shown:\
\fontspec{IBM Plex Mono} \begin{terminaloutput} \small \obeylines \splice{rxdas -h | sed ‘s/\&/\\&/g’} \end{terminaloutput} \fontspec{Minion Pro}
```rexx /* compute sum of numbers 1 to 100 (5050) / options levelb / compute sum of numbers 1 to 100000 */ sum = 0 do i=1 to 100000 sum = i+sum end say “the sum of the numbers 1 to 100000 is:” sum return
This program, when compiled by the 'rxc' compiler, produces the following assembly source:
```rxas <!--sumloop.rxas-->
/*
* SOURCE : sumLoop1000.crexx
*/
.globals=0
main() .locals=4
.meta "sumloop1000.main"="b" ".void" main() ""
setnumdgts 18
setnumfuz 0
setnumfrm 1
setnumcas 1
setnumstd 1
.srcstep 1 1 17 "sumLoop1000.crexx" 4 1 8 "sum = 0"
.meta "sumloop1000.main.sum"="b" ".int" r0
load r0,0
.traceevent "L" 4 "R" "I" "r" 0 1 1 0 "" ""
.traceevent "A" 6 "R" "I" "r" 0 1 1 0 "sum" ""
.srcstep 6 6 17 "sumLoop1000.crexx" 5 1 3 "do i=1 to 100000"
.srcstep 2 2 17 "sumLoop1000.crexx" 5 4 7 "do i=1 to 100000"
.meta "sumloop1000.main.i"="b" ".int" r1
load r1,1
.traceevent "L" 4 "R" "I" "r" 1 2 2 0 "" ""
.traceevent "A" 6 "R" "I" "r" 1 2 2 0 "i" ""
.srcstep 3 3 17 "sumLoop1000.crexx" 5 8 17 "do i=1 to 100000"
load r2,100000
.traceevent "L" 4 "R" "I" "r" 2 0 0 0 "" ""
l7dostart:
.srcstep 3 3 17 "sumLoop1000.crexx" 5 8 17 "do i=1 to 100000"
igt r3,r1,r2
brt l7doend,r3
.srcstep 5 5 17 "sumLoop1000.crexx" 6 4 15 " sum = i+sum"
.traceevent "V" 6 "R" "I" "r" 1 5 5 0 "i" ""
.traceevent "V" 6 "R" "I" "r" 0 5 5 0 "sum" ""
iadd r0,r1,r0
.traceevent "O" 4 "R" "I" "r" 0 5 5 0 "" ""
.traceevent "A" 6 "R" "I" "r" 0 5 5 0 "sum" ""
l7doinc:
.srcstep 4 4 17 "sumLoop1000.crexx" 5 4 5 "do i=1 to 100000"
inc r1
.srcstep 7 7 17 "sumLoop1000.crexx" 7 1 4 "end"
br l7dostart
l7doend:
.srcstep 8 8 17 "sumLoop1000.crexx" 8 1 49 "say \"the sum of the numbers 1 to 100000 is:\" sum"
itos r0
.traceevent "V" 6 "R" "S" "r" 0 8 8 0 "sum" ""
sconcat r3,"the sum of the numbers 1 to 100000 is:",r0
.traceevent "O" 4 "R" "S" "r" 3 8 8 0 "" ""
say r3
.srcstep 9 9 17 "sumLoop1000.crexx" 9 1 7 "return"
ret
.meta "sumloop1000.main.sum"
The assembler produces an ‘rxbin’ file from that. What follows is the disassembly from this ‘rxbin’ file.
```rxas
DESCRIPTION - sumLoop1000
CONSTANT POOL - Size 0x7c0. Dump of EXPOSED entries only (option -p not used):
.globals=0
main() .locals=4 .meta “sumloop1000.main”=”b” “.void” main() “” setnumdgts 18 * 0x000000:00f6 Set Numeric Digits digits=op1 (>4) setnumfuz 0 * 0x000002:00f9 Set Numeric Fuzz digits=op1 (>=0) setnumfrm 1 * 0x000004:00fc Set Numeric Form=op1 (1=sci,2=eng) setnumcas 1 * 0x000006:00ff Set Numeric Case=op1 (1=lower,2=upper) setnumstd 1 * 0x000008:0102 Set Numeric Standard=op1 (1=common,2=classic) .srcstep 1 1 17 “sumLoop1000.crexx” 4 1 8 “sum = 0” .meta “sumloop1000.main.sum”=”b” “.int” r0 load r0,0 * 0x00000a:0001 Load op1 with op2 .traceevent “L” 4 “R” “I” “r” 0 1 1 0 “” “” .traceevent “A” 6 “R” “I” “r” 0 1 1 0 “sum” “” .srcstep 6 6 17 “sumLoop1000.crexx” 5 1 3 “do i=1 to 100000” .srcstep 2 2 17 “sumLoop1000.crexx” 5 4 7 “do i=1 to 100000” .meta “sumloop1000.main.i”=”b” “.int” r1 load r1,1 * 0x00000d:0001 Load op1 with op2 .traceevent “L” 4 “R” “I” “r” 1 2 2 0 “” “” .traceevent “A” 6 “R” “I” “r” 1 2 2 0 “i” “” .srcstep 3 3 17 “sumLoop1000.crexx” 5 8 17 “do i=1 to 100000” load r2,100000 * 0x000010:0001 Load op1 with op2 .traceevent “L” 4 “R” “I” “r” 2 0 0 0 “” “” .srcstep 3 3 17 “sumLoop1000.crexx” 5 8 17 “do i=1 to 100000” lb_13: igtbr lb_1e,r1,r2 * 0x000013:0157 Int Greater than if (op2>op3) goto op1 .srcstep 5 5 17 “sumLoop1000.crexx” 6 4 15 “ sum = i+sum” .traceevent “V” 6 “R” “I” “r” 1 5 5 0 “i” “” .traceevent “V” 6 “R” “I” “r” 0 5 5 0 “sum” “” iadd r0,r1,r0 * 0x000017:000f Integer Add (op1=op2+op3) .traceevent “O” 4 “R” “I” “r” 0 5 5 0 “” “” .traceevent “A” 6 “R” “I” “r” 0 5 5 0 “sum” “” .srcstep 4 4 17 “sumLoop1000.crexx” 5 4 5 “do i=1 to 100000” inc1 * 0x00001b:0020 Increment R1++ Int .srcstep 7 7 17 “sumLoop1000.crexx” 7 1 4 “end” br lb_13 * 0x00001c:0024 Branch to op1 .srcstep 8 8 17 “sumLoop1000.crexx” 8 1 49 “say "the sum of the numbers 1 to 100000 is:" sum” lb_1e: itos r0 * 0x00001e:00e5 Set register string value from its int value .traceevent “V” 6 “R” “S” “r” 0 8 8 0 “sum” “” sconcat r3,”the sum of the numbers 1 to 100000 is:”,r0 * 0x000020:008b String Concat with space (op1=op2||op3) .traceevent “O” 4 “R” “S” “r” 3 8 8 0 “” “” say r3 * 0x000024:01c2 Say op1 .srcstep 9 9 17 “sumLoop1000.crexx” 9 1 7 “return” ret * 0x000026:0030 Return VOID .meta “sumloop1000.main.sum” ```
This file has the output of the disassembler; the procedure name,
main, is identical, but the first label generated by the
compiler, l7dostart: is called lb_9 in the disassembler
output. This is of no consequence for a subsequent re-assembly and
execution of the program.
Do note that the lines are longer than expected, because every disassembled line has the binary representation and a standard explanation of the generated instruction. This makes it easier to find back instructions in an .rxbin load module.
The instructions, however, can be different than expected due to the optimizations the
assembler performs. When the compiler has performed optimizations,
this is already visible in the .rxas file. The assembler optimizations are visible in the disassembled object.
The standard instruction documentation the disassembler affixes is the same as displayed by the rxas -i command, in a line comment after the instructions and their operands.
When stepping through a program using the cRexx Debugger (which is
mentioned in the next chapter), the disassembly is the most
representative record of what is in the .rxbin executable.
as much as possible, given the fact that some information on literals has disappeared ↩