; C Runtime
; L. Stewart, April 7, 1982 5:32 PM
C←CODE SEGMENT
C←DATA SEGMENT
C←DATA ENDS
ASSUME CS:C←CODE, DS:C←DATA, ES:C←DATA
; at the time a c procedure is run, BP holds the frame pointer
; [BP] is the previous frame pointer
; [BP+2] is the pc to return to
; The last procedure argument is passed in BX
; The second to the last argument, if there is one, is passed in CX
; Earlier arguments, if they exist, are PUSHed in order first to
; last before the call.
; We use BP as the "frame pointer"
; f = myframe();
; return the value of BP in BX
←myframe PROC NEAR
MOV BX,BP
RET
←myframe ENDP
; cf = callersframe(f)
; f can be the value returned by myframe or callersframe
←callersframe PROC NEAR
MOV BX,[BX]
RET
←callersframe ENDP
; returnfrom(frame);
; frame had better be on the stack!
; returnfrom(myframe()) is the same as a return
←returnfrom PROC NEAR
MOV SP,BX
POP BP
RET
←returnfrom ENDP
; pc = returnloc(frame);
; aquire the return pc of frame frame
←returnloc PROC NEAR
MOV BX,[BX+2]
RET
←returnloc ENDP
; returnto(frfr, tofr, topc, retval);
; return value retval to location topc in frame tofr, pretending you
; had been executing in frame frfr
; environment on entry:
; frfr
; tofr
; SP -> retadr to use if returning from call to returnto
; CX = topc
; BX = retval
; on entry, SP points to a junk return address. after POPing
; the junk, SP will point to frfr.
; tofr is in CX on entry and topc is in BX
←returnto PROC NEAR
POP BP ; pop garbage return address
POP BP ; set up tofr
POP AX ; get frfr
ADD AX,4 ; pop 'tofr' and 'topc'
MOV SP,AX ; restore SP to the
; value it had before the call
JMP CX ; resume execution
←returnto ENDP
; suppose you want to save enough information to later pretend to return
; value xyz from a procedure called foo. foo will have to do some work:
;
; int frfr, tofr, topc; /* static ! */
;
; foo(foo's arguments) {
; frfr = myframe();
; tofr = callersframe(frfr);
; topc = returnloc(frfr);
; whatever...
; };
;
; later:
; returnto(frfr, tofr, topc, xyz)
;
; The overall problem is that while there is a known amount of space
; between a calling frame and a callee frame, one doesn't know how much
; of it is the caller's locals and how much is the callee's arguments
; call0(proc) calls proc with 0 arguments
←call0 PROC NEAR
JMP BX ; resume execution
←call0 ENDP
; call1(proc, arg) calls proc with 1 argument
←call1 PROC NEAR
JMP CX ; resume execution
←call1 ENDP
; calln(argn-1, argn, arg1, arg2, ..., argn-2, proc, nargs)
; calls proc with arguments arg1, ..., argn
←calln PROC NEAR
MOV AX,CX ; proc
SAL BX,1 ; word index
ADD BX,SP
MOV CX,[BX]
MOV BX,[BX-2]
JMP AX ; resume execution
←calln ENDP
; int ugt(a, b) unsigned compare a and b
←ugt PROC NEAR
CMP CX,BX
JA ugtt
XOR BX,BX
RET
ugtt:
MOV BX,1
RET
←ugt ENDP
; int udiv(a, b) unsigned divide a by b
←udiv PROC NEAR
MOV AX,CX
XOR DX,DX
DIV BX
MOV BX,AX
RET
←udiv ENDP
; int urem(a, b) unsigned remainder of division a by b
←urem PROC NEAR
MOV AX,CX
XOR DX,DX
DIV BX
MOV BX,DX
RET
←urem ENDP
; call
; blt(src, dest, count)
; char *src, *dest;
; int count;
; on entry, count is in BX, dest is in CX, src is on stack
; just above return address
; moves count bytes from src to dest
; assumes all segment registers are 0
←blt PROC NEAR
PUSH BP
MOV BP,SP
MOV SI,[BP+4]
MOV DI,CX
MOV CX,BX
CLD
REP MOVSB
POP BP
RET
←blt ENDP
; Fetch from address in BX and return in BX and AX
←fetchw PROC NEAR
MOV BX,[BX]
MOV AX,BX
RET
←fetchw ENDP
; Store CX to address in BX
←storew PROC NEAR
MOV [BX],CX
RET
←storew ENDP
; Fetch byte from address in BX and return in BL and AL
←fetchb PROC NEAR
MOV BL,[BX]
XOR BH,BH
MOV AX,BX
RET
←fetchb ENDP
; Store CL to address in BX
←storeb PROC NEAR
MOV [BX],CL
RET
←storeb ENDP
; output BL to port CX
←outbyte PROC NEAR
MOV DX,CX
MOV AL,BL
OUT DX,AL
RET
←outbyte ENDP
; input from port BX to BL and AL
←inbyte PROC NEAR
MOV DX,BX
IN AL,DX
MOV BL,AL
RET
←inbyte ENDP
;portstr(p)
; char *p;
; {
; int port;
; int count;
; while(*p != 0x00ff) {
; port = *p++;
; count = *p++;
; while (count--) {
; outbyte(port, *p++);
; };
; };
; };
; enters with BX pointer to port string
←portstr LABEL NEAR
XOR AH,AH
CLD
MOV SI,BX
X16:
LODSB
CMP AL,0FFH
JNE X17
RET
X17:
MOV DX,AX
LODSB
MOV CX,AX
X18:
LODSB
OUT DX,AL
LOOP X18
JMP X16
; swap bytes in BX
←swab PROC NEAR
XCHG BH,BL
RET
←swab ENDP
; SysHalt()
←SysHalt PROC NEAR
HLT
JMP ←SysHalt
RET
←SysHalt ENDP
PUBLIC ←myframe
PUBLIC ←callersframe
PUBLIC ←returnfrom
PUBLIC ←returnloc
PUBLIC ←returnto
PUBLIC ←call0
PUBLIC ←call1
PUBLIC ←calln
PUBLIC ←ugt
PUBLIC ←udiv
PUBLIC ←urem
PUBLIC ←blt
PUBLIC ←fetchw
PUBLIC ←storew
PUBLIC ←fetchb
PUBLIC ←storeb
PUBLIC ←outbyte
PUBLIC ←inbyte
PUBLIC ←portstr
PUBLIC ←swab
PUBLIC ←SysHalt
C←CODE ENDS
END