NASM Forum > Using NASM
LEA or MOV
fredericopissarra:
--- Quote from: munair on November 17, 2021, 09:11:34 AM ---I think it is not a good idea for the simple reason that the stack pointer may change during the execution of a function. Suppose the code within a function calls another function and (local) variables are pushed on the stack to pass them as parameters. How do you access local variables after the stack pointer has changed?
--- End quote ---
That's why compilers like C keeps track of (E|R)SP... Supose you have a funcion f() calling a function g(), each one with one argument, using i386 C callng convention:
--- Code: ---int g(int x) { return x + x; }
int f(int x) { return g(x)+1; }
--- End code ---
The generated code is something like this (without using EBP):
--- Code: ---g:
mov eax,[esp+4]
add eax,eax
ret
f:
mov eax,[esp+4]
push eax
call g
add esp,4 ; stack cleanup. keeps in a known position.
inc eax
ret
--- End code ---
Using the struct approach you'll always sure where arguments and local vars are for a function and don't need to remember the offsets. All you have to do is to pop the pushed argumentos from the stack after the function returns (or before...).
In some compilers (PASCAL, for instance) the responsability for stack cleanup is on the called function ("ret" accepts an argument for that)... The same come, in pascal:
--- Code: ---g:
mov eax,[esp+4]
add eax,eax
ret 4
f:
mov eax,[esp+4]
push eax
call g
inc eax
ret 4
--- End code ---
The point is: Why use prologue/epilogue nowadays? In the old pre-386 processors if you wanted to access data on stack you had two options only: Using POP and using EBP as base pointer in an effective address. It was not possible to use registers other than BP ou BX as base pointer, and other registers than SI or DI as index (and there were no 'scale'), so using BP was mandatory. After 386 this is not the case anymore.
munair:
What is the difference between the struct approach and the stack frame approach other than keeping R/EBP free? Maybe I misunderstand. I have seen examples of GCC (32bits) output producing stack frames, so it still seems a legitimate technique.
Currently in the SharpBASIC compiler the stack cleanup is done after the function call, as it was also messed up with the push instructions before the call. Seems more logical to me, but it's a matter of opinion. Here is a simple, stupid example I used to test function calls in the expression parser:
--- Code: ---' SharpBASIC function
' -------------------
incl "lib/sys.sbi";
decl func five(n: int8): int8;
dim sum: int8;
main do
sum = five(5 * 5) + five(5 + 5);
print sum;
end;
func five(n: int8): int8
do
five = n;
end;
--- End code ---
Generated asm code (without any code optimizations):
--- Code: ---
SECTION .text
global _start
global _end
_start:
movsx eax, byte [_C3]
push eax
movsx eax, byte [_C3]
pop edx
imul edx
push eax
call _I26
add esp, 4
push eax
movsx eax, byte [_C3]
push eax
movsx eax, byte [_C3]
pop edx
add eax, edx
push eax
call _I26
add esp, 4
pop edx
add eax, edx
; save sum
mov [_I27], al
; load sum
movsx eax, byte [_I27]
; print int
mov ebx, _sb_buf12
call _sb_intstr
call _sb_print
call _sb_printlf
_end:
mov ebx, 0
mov eax, 1
int 80h
_I26:
push ebp
mov ebp, esp
sub esp, 4
; init func five
mov byte [ebp - 4], 0
; load n
movsx eax, byte [ebp + 8]
; save func result five
mov [ebp - 4], al
._L0:
; load func result five
movsx eax, byte [ebp - 4]
mov esp, ebp
pop ebp
ret
extern _sb_intstr
extern _sb_print
extern _sb_printlf
extern _sb_buf12
SECTION .rodata
_C3 db 5
SECTION .bss
; define sum
_I27 resb 1
--- End code ---
When you say Pascal compiler, which compiler do you mean? There are several of them, both commercial and free. Same goes for C compilers.
fredericopissarra:
--- Quote from: munair on November 17, 2021, 11:42:14 AM ---What is the difference between the struct approach and the stack frame approach other than keeping R/EBP free? Maybe I misunderstand. I have seen examples of GCC (32bits) output producing stack frames, so it still seems a legitimate technique.
--- End quote ---
Smaller and fastest code. Try to use -fomit-frame-pointer and -O2 options on GCC...
--- Quote ---When you say Pascal compiler, which compiler do you mean? There are several of them, both commercial and free. Same goes for C compilers.
--- End quote ---
Turbo Pascal, Free Pascal and Delphi... And the old "pascal" calling convention used by C compilers back in the 90's, 2000's: Turbo C, Borland C++, MSC6, ...
munair:
When I get to optimization options for the compiler, fomitting the frame pointer will probably be one of them. Thanks again for the suggestion.
Navigation
[0] Message Index
[*] Previous page
Go to full version