my current project is to make a small compiler, for fun. Currently it is able to generate code for subroutine calls.
I want to enable functional programming in my language. But i stumbled upon the problem, that i do not know the address of the label (in the code segment) where the function is which i am passing on the stack. can nasm calculate it for me? how is this handled in other functional languages?
Int main(){subr2(subr);} Int subr2(Int() myfn){return myfn();} Int subr(){return 1;}
How would this (nonsensical) code be translated? I tried to make the smallest example i could.
The problem i see is that you do not know the offset in the code segment of the label (which gets removed by the assembler?) as a compiler that only compiles down until the assembly level.
How can this be solved without much overhead?
Thanks for your time !
EDIT: @Jester pointed out that you can push labels on the stack in assembly
This:
Int main() {
subr2(subr);
}
Int subr2(Int() myfn) {
return myfn();
}
Int subr() {
return 1;
}
Would (without any optimization, and assuming the calling convention isn't awful) become:
main:
mov eax, subr
call subr2
ret
subr2:
call eax
ret
subr:
mov eax,1
ret
With optimization; first you'd inline the subr2()
into main()
to get this:
Int main() {
temp = subr;
return temp();
}
Int subr() {
return 1;
}
Then you'd do some "constant propogation" to get this:
Int main() {
return subr();
}
Int subr() {
return 1;
}
Then you'd inline the subr()
into main()
to get this:
Int main() {
return 1;
}
Then you'd end up with this:
main:
mov eax,1
ret
Note that main()
is just a normal function. Typically there's start-up code that the linker injects into an executable file that initializes things (standard library, heap, etc), calls main()
, and then does exit()
if main()
returns.