; 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