Example #1
0
File: cgen.go Project: g-dx/clarac
func cgenFnCall(node *Node, ops *x64.OpcodeList) {

	// Check function
	fn, ok := node.sym.(*Function)
	if !ok {
		panic(fmt.Sprintf("Unknown symbol: %v, node: %v", node.sym, node))
	}

	switch fn.fnName {
	default:
		ops.CALL(fn.Rva())
	case printlnFuncName:
		cgenPrintCall(node, ops)
	}
}
Example #2
0
File: cgen.go Project: g-dx/clarac
func cgenPrintCall(node *Node, ops *x64.OpcodeList) {

	// Get symbol
	fn, ok := node.sym.(*Function)
	if !ok {
		panic(fmt.Sprintf("Unknown symbol: %v", node.sym))
	}

	// Push the base/frame pointer register value onto stack and overwrite base/frame pointer register to point to
	// the top of stack. This stack pointer can now be modified by us and restored at the end of the function to its
	// previous state

	// TODO: commented out as we must inline this call
	//	ops.PUSH(x64.Rbp)
	//	ops.MOV(x64.Rbp, x64.Rsp)

	// Push values onto stack (string RVA & length)

	str, ok := node.stats[0].sym.(*StringLiteralSymbol)
	if !ok {
		panic(fmt.Sprintf("print function parameter not string literal! - %v", str))
	}
	ops.PUSHI(str.Rva())
	ops.PUSHI(uint32(len(str.Val())))

	// Call print

	ops.CALL(fn.Rva())

	// Clean up stack by overwriting the stack pointer register with the base/frame pointer register. This discards
	// the two values we pushed onto the stack. Then pop the old base/frame pointer value off the stack & back into
	// the base/frame pointer register. This restores the caller's stack.
	// TODO: on x64 we should use 'leave' instruction

	//	ops.MOV(x64.Rsp, x64.Rbp)
	//	ops.POP(x64.Rbp)
	//	ops.RET()
}
Example #3
0
File: cgen.go Project: g-dx/clarac
func cgenFnDecl(node *Node, imports ImportList, ops *x64.OpcodeList) {

	// Get function & set RVA
	fn, ok := node.sym.(*Function)
	if !ok {
		panic(fmt.Sprintf("Unknown symbol: %v, node: %v", node.sym, node.token))
	}
	fn.rva = uint32(ops.Rva())

	ops.PUSH(x64.Rbp)
	ops.MOV(x64.Rbp, x64.Rsp)

	// Generate calls for all functions
	for _, n := range node.stats {
		cgenFnCall(n, ops)
	}

	// Check if we are main - we need to exit!
	if node.token.Val == "main" {
		ops.MOVI(x64.Rcx, 0)
		ops.CALLPTR(imports.funcRva("ExitProcess"))
	} else {
		// TODO: When local variables added must update this!
		ops.MOV(x64.Rsp, x64.Rbp)
		ops.POP(x64.Rbp)
		ops.RET()
	}
}
Example #4
0
File: cgen.go Project: g-dx/clarac
func cgenPrintlnDecl(node *Node, imports ImportList, ops *x64.OpcodeList) {

	// Get function & set RVA
	fn, ok := node.sym.(*Function)
	if !ok {
		panic(fmt.Sprintf("Unknown symbol: %v", node.sym))
	}
	fn.rva = uint32(ops.Rva())

	ops.PUSH(x64.Rbp)
	ops.MOV(x64.Rbp, x64.Rsp)

	// Get the output handle

	ops.MOVI(x64.Rcx, STD_OUTPUT_HANDLE)
	ops.CALLPTR(imports.funcRva("GetStdHandle"))

	// Write to console
	// See [https://msdn.microsoft.com/en-us/library/ms235286.aspx] for more information

	ops.MOV(x64.Rcx, x64.Rax)      // Copy output handle result from AX into register
	ops.MOVM(x64.Rdx, x64.Rbp, 24) // Move string literal RVA into register
	ops.MOVM(x64.R8, x64.Rbp, 16)  // Move string length into register
	ops.MOVI(x64.R9, 0)            // TODO: This should be a local variable on the stack!
	ops.PUSHI(0)
	ops.CALLPTR(imports.funcRva("WriteConsoleA"))

	// Clean stack

	ops.MOV(x64.Rsp, x64.Rbp)
	ops.POP(x64.Rbp)
	ops.RET()
}