Derived operations

Function bodies

body        = {expression}expr semi

| {external} external  semi 

| {inline} inline string semi; 

These give basic semantics to functions.

Let us consider the different forms of body.

expression

  1. setup the frame pointer ( ENTER)
  2. Evaluate the expression on the main stack
  3. pop the stack into a return register
  4. wind back the frame pointer (LEAVE)
  5. return from the function (RET)
  6. in the calling environment, remove the parameters from the stack
  7. push the result on stack

Inline

Note that it is inline

Store away the inline string

Output it on invocation

external routines

Purpose: to call the runtime library in C

Compilation model

Requirements

  1. Must establish a name correspondence with the C routine.
  2. Must pass parameters appropriately
  3. Must get results back from C routines

name correspondence with the C routine

Issues here

  1. Case of the names
  2. allowed characters
  3. how are these passed in assembler

Characters and significance

Case is significant both in Hi and C, but this is not the case of all languages.

Pascal for instance makes case insignificant, and requires that externals where the case is significant be given a name in quotes for example:

procedure close (var f:fileptr); 

external name 'pasclose';

This allows the external routine to have a different name to the internal representation of it. The allowed characters in a name in Hi are limited to the letters, that means we can not call and C routine with an _ or a digit in its name unless we were to extend the syntax for externals along the above lines.

2. Assembler representation

At the headof the assembler file list all the externals as follows:

extern  vconcat 

extern  iota 

extern  putChar 

extern  getNum 

extern  getChar 

extern  putNum 

Then we can call them just as if they were declared within this file.

call vconcat

Underscores

Most 32-bit C compilers share the convention used by 16-bit compilers, that the names of all global symbols (functions or data) they define are formed by prefixing an underscore to the name as it appears in the C program.

However, not all of them do: the `ELF' specification states that C symbols do not have a leading underscore on their assembly-language names.

Thus if you are producing code for Linux, which uses ELF, do not use underscores.

Calling conventions

Some existing conventions:

The C calling convention

  1. The caller pushes the function's parameters on the stack, one after another, in reverse order (right to left, so that the first argument specified to the function is pushed last).
  2. The caller then executes a near `CALL' instruction to pass control to the callee.
  3. The callee receives control, and typically (although this is not actually necessary, in functions which do not need to access their parameters) starts by saving the value of `ESP' in `EBP' so as to be able to use `EBP' as a base pointer to find its parameters on the stack. However, the caller was probably doing this too, so part of the calling convention states that `EBP' must be preserved by any C function. Hence the callee, if it is going to set up `EBP' as a frame pointer, must push the previous value first.
  4. The callee may then access its parameters relative to `EBP'. The doubleword at `[EBP]' holds the previous value of `EBP' as it was pushed; the next doubleword, at `[EBP+4]', holds the return address, pushed implicitly by `CALL'. The parameters start after that, at `[EBP+8]'. The leftmost parameter of the function, since it was pushed last, is accessible at this offset from `EBP'; the others follow, at successively greater offsets. Thus, in a function such as `printf' which takes a variable number of parameters, the pushing of the parameters in reverse order means that the function knows where to find its first parameter, which tells it the number and type of the remaining ones.
  5. The callee may also wish to decrease `ESP' further, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets from `EBP'.
  6. The callee, if it wishes to return a value to the caller, should leave the value in `AL', `AX' or `EAX' depending on the size of the value. Floating-point results are typically returned in `ST0'.
  7. Once the callee has finished processing, it restores `ESP' from `EBP' if it had allocated local stack space, then pops the previous value of `EBP', and returns via `RET' .
  8. When the caller regains control from the callee, the function parameters are still on the stack, so it typically adds an immediate constant to `ESP' to remove them (instead of executing a number of slow `POP' instructions). Thus, if a function is accidentally called with the wrong number of parameters due to a prototype mismatch, the stack will still be returned to a sensible state since the caller, which _knows_ how many parameters it pushed, does the removing.

STDCALL

There is an alternative convention used in windows system calls in which case step 7 becomes :

7. Once the callee has finished processing, it restores `SP' from `BP' if it had allocated local stack space, then pops the previous value of `BP', and returns via `RETF'. It uses the form of `RETF' with an immediate parameter, giving the number of bytes taken up by the parameters on the stack. This causes the parameters to be removed from the stack as a side effect of the return instruction.

Purpose of the std call is to allow calling via call gates

these are data structures in the segment table which allow transfers between privilidge levels and between different tasks.

Function of call gate to

1. Ensure that only secure entry points in the OS can be called

2. Ensure that the stack used by the OS is invisible to user code.

The two stacks

The hardware knows how many parameters there are on the stack from the gate descriptor. It copies them to the new stack, typically the OS stack.

On return parameters are discarded from both stacks using the RET n, instruction which specifies the number of bytes of parameters to pop.

This ensures that even if the parameters are altered by the OS routine these altered values, and the locals of the OS routine remain invisible to the calling environment.

You dont need to handle std-calls for this project, but if you are writing a compiler that is going to call Windows System calls, you need to have this as an auxilliary calling convention.

---

File translated from TEX by TTH, version 3.05.
On
28 Oct 2003, 16:00.