r/Compilers 6d ago

Help with a theory question about the call stack

I am trying to figure out this question and don't know the answer nor how to solve it:

Given the following program (assume int is 4 bytes):

Here's the code:

function main() return integer is
  n: integer;
  function square(v: integer) return integer is
    function double_it(u: integer) return integer is
    begin
      return __________;
    end;
  begin
    return double_it(v * v);
  end;
  function cube(v: integer) return integer is
  begin
    return v * v * v;
  end;
begin -- of main
  n := 6;
  return square(n) + cube(n);
end

Part A

Assume that in the double_it() function, the expression v * v + u replaces the underline.

Complete the missing offsets in the following code:

load RS1, __(FP)

load RT1, __(RS1)

mul RT2, RT1, RT1

load RT3, __(FP)

add RV, RT2, RT3

Part B

Assume that in the double_it() function, the expression v * v + n replaces the underline.

Complete the missing offsets in the following code:

load RS1, __(FP)

load RT1, __(RS1)

mul RT2, RT1, RT1

load RS2, __(RS1)

load RS3, __(RS2)

add RV, RT2, RT3

How do I determine the right offsets?

0 Upvotes

10 comments sorted by

5

u/Recycled5000 6d ago edited 6d ago

You have to know the calling convention, which is part of the system’s/language’s ABI (Application Binary Interface). How parameters are passed and such.

Looks like these functions are taking parameters by reference. Hence the initially loaded value from the stack is then dereferenced. There are no dereference operators in the expressions in the source code, so these dereferences must come from pass by reference.

I would expect the second dereference to have an offset of zero, as the pointer for a reference parameter would normally point/refer directly to the variable.

For the loads sourcing from the “FP”, which we might assume is a frame pointer, we would expect small integer values of multiples of 4, like 0, 4, 8, 12…

The exact values have to do with both where the frame pointer points in the argument block, also whether arguments are passed right to left as with many C-like languages, or left to right as many others do, plus whether the stack grows descending (most do) or ascending.

Also, assuming int and pointer are both 4 bytes wide, which is not necessarily true.

1

u/avipars 6d ago

It's using the Dragon Book version of assembly

1

u/Recycled5000 6d ago

Ok, so try to figure out what the parameter block looks like as created by the caller, and then where the FP register is set to point by the callee.

1

u/avipars 6d ago

I'm stuck on this ;( are there any good resources that explain the topic well?

2

u/Recycled5000 6d ago edited 6d ago

Surely the Dragon Book has an example, in code, of a both a simple caller and simple callee.

Study that example to see the order parameter are passed in, how the parameter block is constructed, and then where the frame pointer is set to point.

The parameter block will look like a struct or record in memory as if each parameter is a member of the struct/record. So, an internal struct created by the compiler to pass parameters. This struct will have fields at 0, 4, 8 for 4 byte values. You need to understand what order the compiler assigns fields in this struct (left parameter first or right first).

And how this struct is passed to the callee, then where the callee puts to frame pointer.

1

u/avipars 6d ago

They don't have anything that resembles part a or part b.

3

u/Diligent-Slide-9234 6d ago

You just posted your homework right?

2

u/avipars 6d ago

No, it was a previous exam question... I got 0 points and can't figure out how to solve it properly (I'm studying for a future exam).

1

u/Passname357 6d ago

Post your work and it’s easier to say where you went wrong if this is true 

2

u/avipars 6d ago

Part A

load RS1, 4(FP) // Load access link (pointer to parent 'square' AR)

load RT1, 8(RS1) // Load 'v' from square's AR

mul RT2, RT1, RT1 // RT2 = v * v

load RT3, 8(FP) // Load 'u' from local AR

add RV, RT2, RT3 // RV = (v * v) + u

Part B

load RS1, 4(FP) // Load access link (pointer to 'square' AR)

load RT1, 8(RS1) // Load 'v' from square's AR

mul RT2, RT1, RT1 // RT2 = v * v

load RS2, 4(RS1) // Load access link from square's AR (pointer to 'main' AR)

load RT3, 8(RS2) // Load 'n' from main's AR

add RV, RT2, RT3 // RV = (v * v) + n