4.5 Relocation
4.5.3 Relocation Types
4.5.3.1 x86 Instruction Relocation
Because of the complexity of the instruction format, relocating operands in instruc- tions is somewhat trickier than relocating addresses and other values in associated runtime information of binaries. Despite the complexity of instruction encoding on the x86 architecture, from the linker’s perspective, the x86 format is easy to handle, since the instruction architecture follows a universal format throughout all x86 in- structions. The x86 series [45] instructions consist of optional instruction prefixes, primary opcode bytes, an addressing-form consisting of the ModR/M byte and some- times the SIB (Scale-Index-Base) byte, a displacement (optional), and an immediate data field (optional).
Instruction relocation is performed while interpreting entries of the relocation in- formation table in Apus images. As Figure4.4 shows, except for the instruction size which is used for debugging purposes, combining patch offset and patch size simpli- fies the relocation for the linker without knowing the instructions. The relocation information is generated along with the compilation of relocatable binaries.
In general, the instruction relocation operation is performed on a data slot in an instruction of the binary. All the necessary information required is described in a link point slot, as we have discussed in Section 4.5.2. The location information of the Link Point, which is the offset of the operand to be modified in the binary, is calculated in the compilation process along with the relocation information. As a consequence, the instruction relocation operation can just modify a data slot in value and relocation are described in a Link Point. That is, the code relocation process does not need to understand the structure of the instruction that needs to be modified.
There are two reason to simplify the instruction relocation steps by moving the in- struction decoding from the linker to the compilation of relocatable binaries. Firstly, the Apus image may be used multiple times and it only takes one compilation cy- cle to generate an Apus image. Secondly, Apus images are not necessary generated during program execution, and compilation time is not a critical criterion any more. The patch size is a safeguard for instruction relocation used as a measure taken during linking to prevent relocation data overflow from the relocation slot and even overlaping to the next instruction in sequence. A relocation overflow is the situation where the size of the data from the Link Point is larger than the available space in
4.5. Relocation 47
000003| JLE 0 | 7E00
000005| PUSH 52[esi] | FF7634
Figure 4.6: An example of a machine instruction sequence
the relocation slot. For example, in Figure4.6 showing an x86 instruction sequence, the instruction JLE [45] only takes an 8-bit immediate (imm) data field, and writing a 16-bit value will certainly overflow the 8-bit imm data field and will also override the following instruction PUSH as well. If an overflow in the relocation slot is detected, the Apus image loading procedure should be aborted and VM_ImageLinkingException thrown. As a consequence, the optimized code for this method will not be available as the image loading fails. However, as we discussed in Section 3.5, the result of program execution should not be affected when the image loading fails.
Only having patch size to protect against relocation overflow is not enough. The machine code generator of the optimising compiler always tries to choose the most suitable instructions for the corresponding MIR (Machine code Intermediate Rep- resentation), and therefore a 8-bit instruction is chosen when the operand of the corresponding MIR is 8-bit, which could potentially cause a relocation overflow if the relocation data is larger than 8-bit. In order to prevent the situation when an in- struction would cause a relocation overflow, the machine code generated is instructed to choose a 32-bit instruction for Link Points regardless of the operand size of the input MIR instruction. It can be argued that choosing a fixed size instruction would waste additional CPU cycles and increase binary size, however, this overhead is in- significant when compared with introducing the possibility of failure in the Apus image loading.
Instruction expansion is an operation to resize an instruction in the binary array. Although expanding an 8-bit instruction into a 32-bit instruction is theoretically plausible, in reality, instruction expansion requires shifting all of the binary after the expanded instruction for an extra space for the relocation slot. In additional, relative addressing used in calls and jumps are affected, and the machine code map used to convert the bytecode offset from the binary offset requires recalculation as well. In order to avoid such situation in the relocation process, choosing a suitable instruction with correct operand size for relocation is important during compilation. Figure 4.10 demonstrates the compiled binary machine code with relocation in-
4.5. Relocation 48
public void example() {
multianewarray m[][] = new multianewarray[3][4]; }
Figure 4.7: Java program using a multianewarray instruction
public void example(); Code:
0: iconst_3 1: iconst_4
2: multianewarray #10, 2; //class "[[Lmultianewarray;" 6: astore_1
7: return
Figure 4.8: Bytecode instruction of the compiled program in Figure4.7
********* START OF IR DUMP Initial HIR FOR < SystemAppCL, Lmultianewarray; >.example ()V -13 LABEL0 Frequency: 0.0
-2 EG ir_prologue l0a(Lmultianewarray;,x,d) = -2 guard_move t1v(GUARD) = <TRUEGUARD> 2 guard_move t3v(GUARD) = <TRUEGUARD> 2 EG newarray t2a([I,p) = [I, 2
2 int_astore 4, t2a([I,p), 1, <mem loc: array < BootstrapCL, I >[]>, <TRUEGUARD> 2 int_astore 3, t2a([I,p), 0, <mem loc: array < BootstrapCL, I >[]>, <TRUEGUARD> 2 guard_move t5v(GUARD) = <TRUEGUARD>
2 EG newobjmultiarray l6a([[Lmultianewarray;,p) = [[Lmultianewarray;, t2a([I,p) -3 return <unused>
-1 bbend BB0 (ENTRY)
********* END OF IR DUMP Initial HIR FOR < SystemAppCL, Lmultianewarray; >.example ()V
Figure 4.9: The HIR translation of multianewarray
formation attached as comments from the program shown in Figure4.7. Figures4.8
and4.9 show the bytecode of program in Figure 4.7and the High-level Intermediate Representation (HIR) of the compiled bytecodes respectively. They are used to help understand the binary code shown in Figure4.10 by showing the implementation of instruction multianewarray before the expansion of the runtime service calls.