procedure Main is g: Integer; procedure A is x: Integer; procedure B is y: Integer; begin y : = x + 1; g := y + 1; end B; procedure C is begin end C; begin end A; procedure D is begin end D; begin end Main; For the program above, when B is invoked, it will access x which is in the AR of A. This means that the AR of A must be located somewhere in the stack. That is, B must be invoked by A either directly (A-->B) or indirectly (for example: A --> C --> B). So the distance from AR of A to AR of B is not known at compiling time. How does the compile generate code to access x in AR of A? The answer is the static link. At run time, when B is invoked, a link to A is built. (This will be explained later.) For example: <-----: the static link of B Main --> D --> A --> B a possible invocation sequence <-----------------: the static link of B Main --> D --> A --> C --> C --> B another invocation sequence The value of the link is usually the fp (frame pointer) of an AR. For the example above, its value is the fp of AR of A. And the link itself, just like return address, is also stored in AR too. Its offset to fp is fixed. So if the value of x is to be loaded into register A. the code may be LDS offset_link(fp) ; load link to register S, register relative mode LDA offset_x(S) ; load x to register A, register relative mode How about the `g' in Main? How to access g from B? The answer are the links, B :--> A and A :--> Main. And these links form the so called static chain. <-----: the static link of B <------------: the static link of A Main --> D --> A --> B a possible invocation sequence <-----------------: the static link of B <------------: the static link of A Main --> D --> A --> C --> C --> B another invocation sequence So if the value of g is to be loaded into register T. the code may be LDS offset_link(fp) ; load link to register S, register relative mode LDS offset_link(S) ; load link to register S, register relative mode LDT offset_g(S) ; load g to register T, register relative mode summary: 1. The static link is built when a subprogram is invoked. 2. The static link points to the fp of AR of its enclosing subprogram. 3. To access a non-local variable, compiler generates code to follow the static links. The number of links traversed is determined by the difference of levels between where the non-local variable resides to current block. For example, if level(Main) = 0, then level(A) = 1 level(B) = 2 level(C) = 2 level(D) = 1 To access x from B, the difference is 2-1=1. Traverse one link. To access g from B, the difference is 2-0=2, Traverse two links. How is the link built? If f calls g, f --> g level K L the link of g has to be built. Since g's link points an AR with level L-1, we simply from f traverse links K-L+1 times. This can be depicted as follows. L-1 K L g' f --> g <---<---<---: links traversed <------------------: link for g Further analysis: case 1: K < L In this case, L = K + 1, so K-L+1 = 0. So g just points to f. For example <------: Main --> D 0 1 case 2: K >= L Traverse K-L+1 links. For example <------------: <-----: <-----: <------------: call C <------------: <------: =====> <------: Main --> D --> A --> C Main --> D --> A --> C --> C 0 1 1 2 0 1 1 2 2 // call B // // \/ <------------------: <------------: <-----: <------------: <------: Main --> D --> A --> C --> C --> B 0 1 1 2 2 2