fix some calling convention stuff
This commit is contained in:
parent
3d44eba388
commit
b88de92fc7
6 changed files with 98 additions and 22 deletions
31
05/codegen.b
31
05/codegen.b
|
@ -1,7 +1,18 @@
|
||||||
; CALLING CONVENTION:
|
; CALLING CONVENTION:
|
||||||
; arguments are pushed onto the stack by the caller, from right to left
|
; Here is the process for calling a function:
|
||||||
; caller must also reserve space on stack for return value
|
; - the caller pushes the arguments on to the stack, from right to left
|
||||||
; so the function puts the return value at [rbp+8] (+8 for stored return address)
|
; - the caller subtracts sizeof(return type) from rsp
|
||||||
|
; - the caller calls the function
|
||||||
|
; - the caller stores away the return value
|
||||||
|
; - the caller adds (sizeof(return type) + sizeof arg0 + ... + sizeof argn) to rsp
|
||||||
|
; STACK LAYOUT:
|
||||||
|
; arg n
|
||||||
|
; ...
|
||||||
|
; arg 0
|
||||||
|
; return value [rbp+16]
|
||||||
|
; return address [rbp+8]
|
||||||
|
; old rbp [rbp]
|
||||||
|
; local variables
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,5 +202,19 @@ function generate_code
|
||||||
codegen_second_pass = 1
|
codegen_second_pass = 1
|
||||||
generate_functions()
|
generate_functions()
|
||||||
; generate code at the entry point of the executable
|
; generate code at the entry point of the executable
|
||||||
|
local main_addr
|
||||||
|
main_addr = ident_list_lookup(functions_addresses, .str_main)
|
||||||
|
if main_addr == 0 goto no_main_function
|
||||||
|
|
||||||
|
; on entry, we will have:
|
||||||
|
; argc = *rsp
|
||||||
|
; argv = rsp + 8
|
||||||
|
|
||||||
|
|
||||||
; @TODO
|
; @TODO
|
||||||
return
|
return
|
||||||
|
:no_main_function
|
||||||
|
die(.str_no_main_function)
|
||||||
|
:str_no_main_function
|
||||||
|
string Error: No main function.
|
||||||
|
byte 0
|
||||||
|
|
|
@ -783,3 +783,6 @@
|
||||||
:str_default
|
:str_default
|
||||||
string default
|
string default
|
||||||
byte 0
|
byte 0
|
||||||
|
:str_main
|
||||||
|
string main
|
||||||
|
byte 0
|
||||||
|
|
|
@ -64,7 +64,7 @@ global statement_datas_ends
|
||||||
; block_static_variables[1] = static variables inside this block inside this function
|
; block_static_variables[1] = static variables inside this block inside this function
|
||||||
; etc.
|
; etc.
|
||||||
global block_static_variables
|
global block_static_variables
|
||||||
; ident lists of (type << 32) | rbp offset; one per block depth
|
; ident lists of (type << 32) | rbp offset; one per block depth -- note that rbp offset may be negative!
|
||||||
global local_variables
|
global local_variables
|
||||||
global block_depth
|
global block_depth
|
||||||
global expressions
|
global expressions
|
||||||
|
|
|
@ -13,5 +13,8 @@ struct A { struct B *blah; }
|
||||||
struct B { struct A *blah; }
|
struct B { struct A *blah; }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int main(void) {
|
int main(int argc, char **Argv) {
|
||||||
|
int i,j;
|
||||||
|
Argv+argc+i;
|
||||||
|
j;
|
||||||
}
|
}
|
||||||
|
|
41
05/parse.b
41
05/parse.b
|
@ -239,21 +239,31 @@ function parse_toplevel_declaration
|
||||||
string Functions should not have initializers.
|
string Functions should not have initializers.
|
||||||
byte 0
|
byte 0
|
||||||
:parse_function_definition
|
:parse_function_definition
|
||||||
|
local ret_type
|
||||||
|
local param_offset
|
||||||
|
|
||||||
if block_depth != 0 goto nested_function
|
if block_depth != 0 goto nested_function
|
||||||
if function_param_has_no_name != 0 goto function_no_param_name
|
if function_param_has_no_name != 0 goto function_no_param_name
|
||||||
p = types + type
|
p = types + type
|
||||||
if *1p != TYPE_FUNCTION goto lbrace_after_declaration
|
if *1p != TYPE_FUNCTION goto lbrace_after_declaration
|
||||||
|
|
||||||
|
ret_type = functype_return_type(type)
|
||||||
|
|
||||||
global function_stmt_data ; initialized in main
|
global function_stmt_data ; initialized in main
|
||||||
global function_stmt_data_bytes_used
|
global function_stmt_data_bytes_used
|
||||||
|
|
||||||
local_var_rbp_offset = 0
|
|
||||||
|
|
||||||
out = function_stmt_data + function_stmt_data_bytes_used
|
out = function_stmt_data + function_stmt_data_bytes_used
|
||||||
out0 = out
|
out0 = out
|
||||||
ident_list_add(function_statements, name, out)
|
ident_list_add(function_statements, name, out)
|
||||||
|
|
||||||
; deal with function parameters
|
; deal with function parameters
|
||||||
|
; function parameters go above return value on the stack
|
||||||
|
n = type_sizeof(ret_type)
|
||||||
|
n += 7
|
||||||
|
n >= 3
|
||||||
|
n <= 3
|
||||||
|
param_offset = n + 16 ; + 16 for old rbp and return address
|
||||||
|
|
||||||
p = type + 1
|
p = type + 1
|
||||||
name = function_param_names
|
name = function_param_names
|
||||||
list = local_variables
|
list = local_variables
|
||||||
|
@ -261,18 +271,21 @@ function parse_toplevel_declaration
|
||||||
list = *8list
|
list = *8list
|
||||||
:fn_params_loop
|
:fn_params_loop
|
||||||
if *1name == 0 goto fn_params_loop_end
|
if *1name == 0 goto fn_params_loop_end
|
||||||
local_var_rbp_offset += type_sizeof(p)
|
|
||||||
local_var_rbp_offset += 7
|
|
||||||
local_var_rbp_offset >= 3
|
|
||||||
local_var_rbp_offset <= 3
|
|
||||||
c = p < 32
|
c = p < 32
|
||||||
c |= local_var_rbp_offset
|
c |= param_offset
|
||||||
ident_list_add(list, name, c)
|
ident_list_add(list, name, c)
|
||||||
|
param_offset += type_sizeof(p)
|
||||||
|
param_offset += 7
|
||||||
|
param_offset >= 3
|
||||||
|
param_offset <= 3
|
||||||
p += type_length(p)
|
p += type_length(p)
|
||||||
name = memchr(name, 0)
|
name = memchr(name, 0)
|
||||||
name += 1
|
name += 1
|
||||||
goto fn_params_loop
|
goto fn_params_loop
|
||||||
:fn_params_loop_end
|
:fn_params_loop_end
|
||||||
|
|
||||||
|
local_var_rbp_offset = 0
|
||||||
|
|
||||||
; NOTE: it's the caller's responsibility to properly set rsp to accomodate all the arguments.
|
; NOTE: it's the caller's responsibility to properly set rsp to accomodate all the arguments.
|
||||||
; it needs to be this way because of varargs functions (the function doesn't know how many arguments there are).
|
; it needs to be this way because of varargs functions (the function doesn't know how many arguments there are).
|
||||||
parse_statement(&token, &out)
|
parse_statement(&token, &out)
|
||||||
|
@ -698,8 +711,9 @@ function parse_statement
|
||||||
out += 24
|
out += 24
|
||||||
p = local_variables
|
p = local_variables
|
||||||
p += block_depth < 3
|
p += block_depth < 3
|
||||||
l_offset = local_var_rbp_offset
|
; local variables are stored below rbp
|
||||||
c = l_offset
|
l_offset = 0 - local_var_rbp_offset
|
||||||
|
c = l_offset & 0xffffffff
|
||||||
c |= l_type < 32
|
c |= l_type < 32
|
||||||
ident_list_set(*8p, l_name, c)
|
ident_list_set(*8p, l_name, c)
|
||||||
|
|
||||||
|
@ -3080,7 +3094,8 @@ function parse_expression
|
||||||
out += 4
|
out += 4
|
||||||
*4out = c > 32 ; extract type
|
*4out = c > 32 ; extract type
|
||||||
out += 4
|
out += 4
|
||||||
*8out = c & 0xffffffff ; extract rbp offset
|
c &= 0xffffffff
|
||||||
|
*8out = sign_extend_32_to_64(c) ; extract rbp offset
|
||||||
out += 8
|
out += 8
|
||||||
return out
|
return out
|
||||||
:expression_integer
|
:expression_integer
|
||||||
|
@ -4074,12 +4089,12 @@ function print_expression
|
||||||
:print_local_variable
|
:print_local_variable
|
||||||
puts(.str_local_prefix)
|
puts(.str_local_prefix)
|
||||||
expression += 8
|
expression += 8
|
||||||
putn(*8expression)
|
putn_with_sign(*8expression)
|
||||||
putc('])
|
putc('])
|
||||||
expression += 8
|
expression += 8
|
||||||
return expression
|
return expression
|
||||||
:str_local_prefix
|
:str_local_prefix
|
||||||
string [rbp-
|
string [rbp
|
||||||
byte 0
|
byte 0
|
||||||
:print_expr_function
|
:print_expr_function
|
||||||
expression += 8
|
expression += 8
|
||||||
|
|
38
05/util.b
38
05/util.b
|
@ -1,3 +1,11 @@
|
||||||
|
function sign_extend_32_to_64
|
||||||
|
argument n
|
||||||
|
local c
|
||||||
|
c = n > 31
|
||||||
|
n |= c * 0xffffffff00000000
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
; multiply two 64-bit signed numbers to a 128-bit number
|
; multiply two 64-bit signed numbers to a 128-bit number
|
||||||
function full_multiply_signed
|
function full_multiply_signed
|
||||||
argument a
|
argument a
|
||||||
|
@ -456,15 +464,27 @@ function fputn_signed
|
||||||
argument fd
|
argument fd
|
||||||
argument n
|
argument n
|
||||||
if n < 0 goto fputn_negative
|
if n < 0 goto fputn_negative
|
||||||
|
fputn(fd, n)
|
||||||
fputn(fd, n)
|
return
|
||||||
return
|
|
||||||
|
|
||||||
:fputn_negative
|
:fputn_negative
|
||||||
fputc(fd, '-)
|
fputc(fd, '-)
|
||||||
n = 0 - n
|
n = 0 - n
|
||||||
fputn(fd, n)
|
fputn(fd, n)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
; like fputn_signed, but include the sign even if it's zero or positive
|
||||||
|
function fputn_with_sign
|
||||||
|
argument fd
|
||||||
|
argument n
|
||||||
|
if n < 0 goto fputn_with_sign_negative
|
||||||
|
fputc(fd, '+)
|
||||||
|
fputn(fd, n)
|
||||||
|
return
|
||||||
|
:fputn_with_sign_negative
|
||||||
|
fputc(fd, '-)
|
||||||
|
n = 0 - n
|
||||||
|
fputn(fd, n)
|
||||||
|
return
|
||||||
|
|
||||||
:hex_digits
|
:hex_digits
|
||||||
string 0123456789abcdef
|
string 0123456789abcdef
|
||||||
|
@ -527,6 +547,11 @@ function putn_signed
|
||||||
fputn_signed(1, n)
|
fputn_signed(1, n)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
function putn_with_sign
|
||||||
|
argument n
|
||||||
|
fputn_with_sign(1, n)
|
||||||
|
return
|
||||||
|
|
||||||
function putnln
|
function putnln
|
||||||
argument n
|
argument n
|
||||||
fputn(1, n)
|
fputn(1, n)
|
||||||
|
@ -539,6 +564,11 @@ function putnln_signed
|
||||||
fputc(1, 10)
|
fputc(1, 10)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
function putnln_with_sign
|
||||||
|
argument n
|
||||||
|
fputn_with_sign(1, n)
|
||||||
|
fputc(1, 10)
|
||||||
|
return
|
||||||
|
|
||||||
function fputc
|
function fputc
|
||||||
argument fd
|
argument fd
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue