5. Function definitions

Now we get to the interesting part. For each subroutine in the original source file, Relogix outputs a C function. (It may also create functions corresponding to code fragments which were not truly subroutines in the original assembler).

Here we have just one function, movetok. It begins with a standardized comment block, which includes any comment which was originally attached to the subroutine in the original assembler file. It also includes a standard description of the parameters and result (if any) of the function. The function itself follows.

Function prototype

Looking at the translation of movetok in the above example, you can see that Relogix has determined that the function takes two arguments, corresponding to the A0 and A1 registers in the original source file (ESI and EDI in the x86 version). This choice arises because these are the only registers used as inputs by the assembler subroutine.

Relogix has also translated the subroutine to a function which does not return a result. This is less obvious, because the assembler subroutine actually changes four registers, including D0 and D1 (ECX and EAX in the x86 version), as well as the input A0 and A1 registers. Looking at this code in isolation, it seems likely that D0 is not a result of the function (because it would always contain the value 0 on exit), but it is not possible to be sure that D1 is not a result - it could be that callers of this routine would look at D1 to see whether the loop terminated because ENDMARK was reached in the loop. It might even be that the values in A0 and A1 are needed after the routine completes. How can Relogix be sure that the translation is correct?

The answer is that Relogix does not translate the subroutine in isolation. Instead, it examines every assembler file in the set of sources you are translating, and keeps track of the register usage after each subroutine call. It thus knows whether a particular register is needed at the end of this subroutine, and is able to choose the function prototype accordingly. If there is more than one returned item, Relogix handles this by passing a pointer to the argument.

This means that, to generate a correct translation, Relogix must be used to translate every assembler file in the set of sources which were originally linked together, unless you supply it with the interface information yourself (through a user-supplied header file).

In addition to data passed in registers, Relogix also handles parameters and results passed on the stack or in condition codes. For example, if a subroutine was written to set the overflow flag on arithmetic overflow (that is, if callers of the subroutine checked overflow after it returned), the overflow condition would be represented in C by a Boolean result.