From 29c57b53f56e1191d6165a376fa2a583acbc8131 Mon Sep 17 00:00:00 2001 From: Toshi Piazza Date: Tue, 18 Jan 2022 02:21:48 -0800 Subject: [PATCH] Fixes disassembly and pcode for instructions which read gp For instructions which read C11 aka the gp register, such as L2_loadrubgp, gp should only be consulted if an immext was *not* applied. For example, immext is applied below so the memref is not gp-rel: { immext(##0x123440) R0 = memw(#0+##0x123450) jumpr R31 } But this is gp-rel: { R0 = memw(GP+##0x10) jumpr R31 } Fixes this issue by adding a "gp" sleigh constructor that's conditional on the immext context reg, and adds C11 or 0 as an operand based on the above Fixes #5 --- .../Hexagon/data/languages/hexagon.slaspec | 71 +++++++++-------- .../HexagonPacketTestDisassembly.java | 77 +++++++++++++++++++ 2 files changed, 117 insertions(+), 31 deletions(-) diff --git a/Ghidra/Processors/Hexagon/data/languages/hexagon.slaspec b/Ghidra/Processors/Hexagon/data/languages/hexagon.slaspec index ba2cc2bd9e..4194ed3853 100644 --- a/Ghidra/Processors/Hexagon/data/languages/hexagon.slaspec +++ b/Ghidra/Processors/Hexagon/data/languages/hexagon.slaspec @@ -12390,6 +12390,15 @@ C4_addipc_pkt_start: reloc is epsilon [ reloc = pkt_start; ] { tmp = reloc:4; export tmp; } +# 172 is address of C11, so C11 appears in the operands list +gp: reloc is immext = 0xffffffff [ reloc = 172; ] { + export *[register]:4 reloc; +} + +gp: reloc is epsilon [ reloc = 0; ] { + tmp:4 = 0; export tmp; +} + :J2_jump J2_jump_r22_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b25 = 0 & b26 = 0 & b27 = 1 & b28 = 1 & b29 = 0 & b30 = 1 & b31 = 0 & J2_jump_r22_2 { goto J2_jump_r22_2; } @@ -25007,58 +25016,58 @@ C4_addipc_pkt_start: reloc is epsilon [ reloc = pkt_start; ] { *:4 EA = S4_storeiri_io_S8; } -:L2_loadrubgp L2_loadrubgp_Rd32 L2_loadrubgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 1 & b22 = 0 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & L2_loadrubgp_Rd32 & L2_loadrubgp_u16_0 { +:L2_loadrubgp L2_loadrubgp_Rd32 gp L2_loadrubgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 1 & b22 = 0 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & L2_loadrubgp_Rd32 & L2_loadrubgp_u16_0 { local EA:4; local tmp0:4; - tmp0 = C11 + L2_loadrubgp_u16_0; + tmp0 = gp + L2_loadrubgp_u16_0; EA = tmp0; L2_loadrubgp_Rd32 = *:1 EA; } -:L2_loadrbgp L2_loadrbgp_Rd32 L2_loadrbgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & L2_loadrbgp_Rd32 & L2_loadrbgp_u16_0 { +:L2_loadrbgp L2_loadrbgp_Rd32 gp L2_loadrbgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & L2_loadrbgp_Rd32 & L2_loadrbgp_u16_0 { local EA:4; local tmp0:4; - tmp0 = C11 + L2_loadrbgp_u16_0; + tmp0 = gp + L2_loadrbgp_u16_0; EA = tmp0; L2_loadrbgp_Rd32 = *:1 EA; } -:L2_loadruhgp L2_loadruhgp_Rd32 L2_loadruhgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 1 & b22 = 1 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & L2_loadruhgp_Rd32 & L2_loadruhgp_u16_1 { +:L2_loadruhgp L2_loadruhgp_Rd32 gp L2_loadruhgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 1 & b22 = 1 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & L2_loadruhgp_Rd32 & L2_loadruhgp_u16_1 { local EA:4; local tmp0:4; - tmp0 = C11 + L2_loadruhgp_u16_1; + tmp0 = gp + L2_loadruhgp_u16_1; EA = tmp0; L2_loadruhgp_Rd32 = *:2 EA; } -:L2_loadrhgp L2_loadrhgp_Rd32 L2_loadrhgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & L2_loadrhgp_Rd32 & L2_loadrhgp_u16_1 { +:L2_loadrhgp L2_loadrhgp_Rd32 gp L2_loadrhgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 0 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & L2_loadrhgp_Rd32 & L2_loadrhgp_u16_1 { local EA:4; local tmp0:4; - tmp0 = C11 + L2_loadrhgp_u16_1; + tmp0 = gp + L2_loadrhgp_u16_1; EA = tmp0; L2_loadrhgp_Rd32 = *:2 EA; } -:L2_loadrigp L2_loadrigp_Rd32 L2_loadrigp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 1 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & L2_loadrigp_Rd32 & L2_loadrigp_u16_2 { +:L2_loadrigp L2_loadrigp_Rd32 gp L2_loadrigp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 1 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & L2_loadrigp_Rd32 & L2_loadrigp_u16_2 { local EA:4; local tmp0:4; - tmp0 = C11 + L2_loadrigp_u16_2; + tmp0 = gp + L2_loadrigp_u16_2; EA = tmp0; L2_loadrigp_Rd32 = *:4 EA; } -:L2_loadrdgp L2_loadrdgp_Rdd32 L2_loadrdgp_u16_3 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 1 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & L2_loadrdgp_Rdd32 & L2_loadrdgp_u16_3 { +:L2_loadrdgp L2_loadrdgp_Rdd32 gp L2_loadrdgp_u16_3 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 1 & b24 = 1 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & L2_loadrdgp_Rdd32 & L2_loadrdgp_u16_3 { local EA:4; local tmp0:4; - tmp0 = C11 + L2_loadrdgp_u16_3; + tmp0 = gp + L2_loadrdgp_u16_3; EA = tmp0; L2_loadrdgp_Rdd32 = *:8 EA; } -:S2_storerbgp S2_storerbgp_Rt32 S2_storerbgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 0 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerbgp_Rt32 & S2_storerbgp_u16_0 { +:S2_storerbgp S2_storerbgp_Rt32 gp S2_storerbgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 0 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerbgp_Rt32 & S2_storerbgp_u16_0 { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerbgp_u16_0; + tmp0 = gp + S2_storerbgp_u16_0; EA = tmp0; local tmp1:1; local tmp2:4; @@ -25077,10 +25086,10 @@ C4_addipc_pkt_start: reloc is epsilon [ reloc = pkt_start; ] { *:1 EA = tmp1; } -:S2_storerhgp S2_storerhgp_Rt32 S2_storerhgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 0 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerhgp_Rt32 & S2_storerhgp_u16_1 { +:S2_storerhgp S2_storerhgp_Rt32 gp S2_storerhgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 0 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerhgp_Rt32 & S2_storerhgp_u16_1 { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerhgp_u16_1; + tmp0 = gp + S2_storerhgp_u16_1; EA = tmp0; local tmp1:2; local tmp2:4; @@ -25099,10 +25108,10 @@ C4_addipc_pkt_start: reloc is epsilon [ reloc = pkt_start; ] { *:2 EA = tmp1; } -:S2_storerfgp S2_storerfgp_Rt32 S2_storerfgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 1 & b22 = 1 & b23 = 0 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerfgp_Rt32 & S2_storerfgp_u16_1 { +:S2_storerfgp S2_storerfgp_Rt32 gp S2_storerfgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 1 & b22 = 1 & b23 = 0 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerfgp_Rt32 & S2_storerfgp_u16_1 { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerfgp_u16_1; + tmp0 = gp + S2_storerfgp_u16_1; EA = tmp0; local tmp1:2; local tmp2:4; @@ -25121,40 +25130,40 @@ C4_addipc_pkt_start: reloc is epsilon [ reloc = pkt_start; ] { *:2 EA = tmp1; } -:S2_storerigp S2_storerigp_Rt32 S2_storerigp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerigp_Rt32 & S2_storerigp_u16_2 { +:S2_storerigp S2_storerigp_Rt32 gp S2_storerigp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerigp_Rt32 & S2_storerigp_u16_2 { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerigp_u16_2; + tmp0 = gp + S2_storerigp_u16_2; EA = tmp0; *:4 EA = S2_storerigp_Rt32; } -:S2_storerdgp S2_storerdgp_Rtt32 S2_storerdgp_u16_3 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerdgp_Rtt32 & S2_storerdgp_u16_3 { +:S2_storerdgp S2_storerdgp_Rtt32 gp S2_storerdgp_u16_3 is phase = 1 & Parse != 0b00 & subinsn = 0 & b21 = 0 & b22 = 1 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerdgp_Rtt32 & S2_storerdgp_u16_3 { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerdgp_u16_3; + tmp0 = gp + S2_storerdgp_u16_3; EA = tmp0; *:8 EA = S2_storerdgp_Rtt32; } -:S2_storerinewgp S2_storerinewgp_Nt8 S2_storerinewgp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 1 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerinewgp_Nt8 & S2_storerinewgp_u16_2 & hasnew = 0 unimpl +:S2_storerinewgp S2_storerinewgp_Nt8 gp S2_storerinewgp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 1 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerinewgp_Nt8 & S2_storerinewgp_u16_2 & hasnew = 0 unimpl -:S2_storerinewgp dotnewreg S2_storerinewgp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 1 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerinewgp_Nt8 & S2_storerinewgp_u16_2 & dotnewreg { +:S2_storerinewgp dotnewreg gp S2_storerinewgp_u16_2 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 1 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerinewgp_Nt8 & S2_storerinewgp_u16_2 & dotnewreg { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerinewgp_u16_2; + tmp0 = gp + S2_storerinewgp_u16_2; EA = tmp0; local tmp1:4; tmp1 = newreg(dotnewreg); *:4 EA = tmp1; } -:S2_storerbnewgp S2_storerbnewgp_Nt8 S2_storerbnewgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerbnewgp_Nt8 & S2_storerbnewgp_u16_0 & hasnew = 0 unimpl +:S2_storerbnewgp S2_storerbnewgp_Nt8 gp S2_storerbnewgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerbnewgp_Nt8 & S2_storerbnewgp_u16_0 & hasnew = 0 unimpl -:S2_storerbnewgp dotnewreg S2_storerbnewgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerbnewgp_Nt8 & S2_storerbnewgp_u16_0 & dotnewreg { +:S2_storerbnewgp dotnewreg gp S2_storerbnewgp_u16_0 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 0 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerbnewgp_Nt8 & S2_storerbnewgp_u16_0 & dotnewreg { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerbnewgp_u16_0; + tmp0 = gp + S2_storerbnewgp_u16_0; EA = tmp0; local tmp1:1; local tmp2:4; @@ -25175,12 +25184,12 @@ C4_addipc_pkt_start: reloc is epsilon [ reloc = pkt_start; ] { *:1 EA = tmp1; } -:S2_storerhnewgp S2_storerhnewgp_Nt8 S2_storerhnewgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 1 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerhnewgp_Nt8 & S2_storerhnewgp_u16_1 & hasnew = 0 unimpl +:S2_storerhnewgp S2_storerhnewgp_Nt8 gp S2_storerhnewgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 1 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerhnewgp_Nt8 & S2_storerhnewgp_u16_1 & hasnew = 0 unimpl -:S2_storerhnewgp dotnewreg S2_storerhnewgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 1 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & S2_storerhnewgp_Nt8 & S2_storerhnewgp_u16_1 & dotnewreg { +:S2_storerhnewgp dotnewreg gp S2_storerhnewgp_u16_1 is phase = 1 & Parse != 0b00 & subinsn = 0 & b11 = 1 & b12 = 0 & b21 = 1 & b22 = 0 & b23 = 1 & b24 = 0 & b27 = 1 & b28 = 0 & b29 = 0 & b30 = 1 & b31 = 0 & gp & S2_storerhnewgp_Nt8 & S2_storerhnewgp_u16_1 & dotnewreg { local EA:4; local tmp0:4; - tmp0 = C11 + S2_storerhnewgp_u16_1; + tmp0 = gp + S2_storerhnewgp_u16_1; EA = tmp0; local tmp1:2; local tmp2:4; diff --git a/Ghidra/Processors/Hexagon/src/test.slow/java/ghidra/app/plugin/core/analysis/HexagonPacketTestDisassembly.java b/Ghidra/Processors/Hexagon/src/test.slow/java/ghidra/app/plugin/core/analysis/HexagonPacketTestDisassembly.java index 9af82ffd18..748f434b1f 100644 --- a/Ghidra/Processors/Hexagon/src/test.slow/java/ghidra/app/plugin/core/analysis/HexagonPacketTestDisassembly.java +++ b/Ghidra/Processors/Hexagon/src/test.slow/java/ghidra/app/plugin/core/analysis/HexagonPacketTestDisassembly.java @@ -25,6 +25,7 @@ import ghidra.framework.options.Options; import ghidra.program.database.ProgramBuilder; +import ghidra.program.model.address.Address; import ghidra.program.model.address.UniqueAddressFactory; import ghidra.program.model.lang.ParallelInstructionLanguageHelper; import ghidra.program.model.lang.Register; @@ -33,6 +34,7 @@ import ghidra.program.model.listing.InstructionIterator; import ghidra.program.model.listing.Program; import ghidra.program.model.pcode.PcodeOp; +import ghidra.program.model.scalar.Scalar; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; @@ -337,4 +339,79 @@ public void testEndloop0() throws Exception { assertEquals(parallelHelper.getMnemonicSuffix(endloop), "}:endloop0"); } + boolean isGpInPcode(Instruction instr) { + boolean foundGp = false; + Address gp = program.getRegister("C11").getAddress(); + for (PcodeOp op : instr.getPcode()) { + for (int i = 0; i < op.getNumInputs(); ++i) { + if (op.getInput(i).getAddress().equals(gp)) { + foundGp = true; + break; + } + } + if (op.getOutput().equals(gp)) { + foundGp = true; + break; + } + } + return foundGp; + } + + @Test + public void testGpImm() throws Exception { + ProgramBuilder programBuilder = new ProgramBuilder("Test", "hexagon:LE:32:default"); + program = programBuilder.getProgram(); + int txId = program.startTransaction("Add Memory"); + programBuilder.createMemory(".text", "1000", 12); + + programBuilder.setBytes("1000", "d1 48 01 00 00 c2 80 49 00 c0 9f 52"); + + programBuilder.disassemble("1000", 12, true); + programBuilder.analyze(); + + program.endTransaction(txId, true); + + printInstructions(); + + Instruction imm_load = program.getListing().getInstructionAt(programBuilder.addr("1004")); + + // verify opnd is 0 + Object[] obj = imm_load.getOpObjects(1); + assertEquals(1, obj.length); + Object obj2 = obj[0]; + assert obj2 instanceof Scalar; + Scalar s = (Scalar) obj2; + assertEquals(0, s.getUnsignedValue()); + + assert !isGpInPcode(imm_load); + } + + @Test + public void testGpRel() throws Exception { + ProgramBuilder programBuilder = new ProgramBuilder("Test", "hexagon:LE:32:default"); + program = programBuilder.getProgram(); + int txId = program.startTransaction("Add Memory"); + programBuilder.createMemory(".text", "1000", 8); + + programBuilder.setBytes("1000", "80 c0 80 49 00 c0 9f 52"); + + programBuilder.disassemble("1000", 8, true); + programBuilder.analyze(); + + program.endTransaction(txId, true); + + printInstructions(); + + Instruction rel_load = program.getListing().getInstructionAt(programBuilder.addr("1000")); + + // verify opnd is C11 + Object[] obj = rel_load.getOpObjects(1); + assertEquals(1, obj.length); + Object obj2 = obj[0]; + assert obj2 instanceof Register; + Register s = (Register) obj2; + assertEquals(s, program.getRegister("C11")); + + assert isGpInPcode(rel_load); + } }