4 ms·
push ebp move ebp, esp sub esp, fun_0_stacksize ; calculating foo() and saving the temporary call foo push eax ; loading the temporary
by Joker_vD 6y ago
push ebp
move ebp, esp
sub esp, fun_0_stacksize
; calculating foo() and saving the temporary
call foo
push eax
; loading the temporary and...
pop eax
; ...assigning it to "a"
mov [ebp+fun_0_var_a], eax
; calculating "a+1" starts by evaluating "a"...
mov eax, [ebp+fun_0_var_a]
; ...and saving it as a temporary...
push eax
; ..then by evaluating 1
mov eax, 1
; ...and saving it as a temporary
push eax
; then you load two temporaries, add them together...
pop ebx
pop eax
add eax, ebx
; ...and save the temporary result
push eax
; then you load the temporary result and...
pop eax
; ...save it as "b"
mov [ebp+fun_0_var_b], eax
; at this point, you know the total number of local variables
; the "fun_NNN_" prefix is used because EQU constants cannot be
; redefined (obviously, or they wouldn't support forward uses)
fun_0_stacksize EQU 8
fun_0_var_a EQU -4
fun_0_var_b EQU -8
; epilogue
mov esp, ebp
pop ebp
retn
Notice how accessing the locals is done via a separate Base Pointer register EBP instead of the Stack Pointer register ESP (in fact, ESP-based addressing mode is encoded really, really ugly on x86), so that pushing&popping of temporaries doesn't mess up the loads/stores of local variables.
Yes, the code quality is appalling but... it works. In fact, I think Nils M. Holm's T3X compiler uses a similar approach as well.
Of course, if you can allow yourself to use some IR, you can actually assign registers to variables and temporaries and do a much better job.