<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto">Peter<div><br><blockquote type="cite"><div dir="ltr"><span>From: Andreas Pirklbauer <andreas_pirklbauer@yahoo.com></span><br><span>Date: Mon, 18 Nov 2019 21:04:32 +0100</span><br><blockquote type="cite"><span>the compiler generates the instruction </span><br></blockquote><blockquote type="cite"><span>| BL (4) | cond (4) | mno (4) | pno (8) | pc-fixorgP (12) |,</span><br></blockquote><span></span><br></div></blockquote>Your question deep dives directly into the very tricky (and nasty) implementation details of the compiler.</div><div>And unfortunately to say, „the RISC architecture“ will not help at all to understand what the compiler generates here.</div><div><br></div><div>Normally, you may assume that the compiler generates assembler instructions that comply to the RISC5 architecture. But there are exceptions to this rule, where the compiler does something completely different. And the mentioned example above is unfortunately one if those few exceptions.</div><div><br></div><div>What is the problem the compiler has to solve? It‘s about „seperate compilation“ and „dynamic module loading“.</div><div>You know, that in Oberon you can write</div><div> MODULE B;</div><div> IMPORT A;</div><div> BEGIN A.P; END B.</div><div>A<span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">t compile time of B, the compiler does not know at what memory address the code of module A is loaded by the loader. That means the compiler can not use ABSOLUTE memory addresses in branch/jump instructions to A.P. The compiler needs to generate somehow code with RELATIVE offsets to the start of P.</span></div><div><span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"><br></span></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);">To complicate things, Oberon allows to change the implementation of procedure P in module A without the need to recompile B. That makes the code generation for A.P in module B even worse as even the relative offset of the start of P may change from compilation of A to the next compilation of A.</span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);"><br></span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);">In short, the compiler can not solve this without help. The only instance that knows where in memory the module A and B are located is the loader (Modules.Load) and the loader also keeps a list of start offsets to all exported procedures.</span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);">In this case, the compiler does NOT generate a valid RISC5 assembler instruction, but instead a command for the loader what he has to do. After loading the code into memory, the loader modifies all jump instructions to imported procedures. To do so, the loader needs a module number for A and a procedure number of P. It looks up in his internal tables where currently A is located and where procedure P currently starts, calculates the correct address and generates a valid RISC5 jump instruction.</span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);"><br></span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);">I hope my explanation helped a little and does not confuse..</span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);"><br></span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);">br</span></font></div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);">Jörg</span></font></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div>does not help here</div></body></html>