函数式编程如何在汇编级别工作?

How does functional programming work at the assembly level?

我目前的项目是为了好玩而制作一个小型编译器。 目前它能够为子程序调用生成代码。

我想用我的语言启用函数式编程。 但是我偶然发现了这个问题,我不知道我在堆栈上传递的函数所在的标签地址(在代码段中)。 nasm 可以帮我计算一下吗?这在其他函数式语言中是如何处理的?

Int main(){subr2(subr);} Int subr2(Int() myfn){return myfn();} Int subr(){return 1;}

如何翻译这段(无意义的)代码? 我尽量举出最小的例子。

我看到的问题是你不知道标签的代码段中的偏移量(它被汇编程序删除了?)作为编译器向下编译直到装配层。

如何在没有太多开销的情况下解决这个问题?

感谢您的宝贵时间!

编辑: @Jester 指出你可以在 assembly

中将标签压入堆栈

@Jester 有解决方案。 事实上,您可以在汇编中将标签推送到堆栈。

示例代码:

   section  .text

   global _start     ;must be declared for linker (ld)

   _start:              ;tells linker entry point

   push subr ; pushing label on stack
   pop eax ; 
   push _start_continue; together these 2 should make a 'call'
   jmp eax    ;

   _start_continue:

   mov eax,1; sys_exit
   int 0x80;

   subr:

   mov  edx,len     ;message length
   mov  ecx,msg     ;message to write
   mov  ebx,1       ;file descriptor (stdout)
   mov  eax,4       ;system call number (sys_write)
   int  0x80        ;call kernel

   ret;

这个:

Int main() {
    subr2(subr);
}

Int subr2(Int() myfn) {
    return myfn();
}

Int subr() {
    return 1;
}

会(没有任何优化,并且假设调用约定并不糟糕)变成:

main:
  mov eax, subr
  call subr2
  ret

subr2:
    call eax
    ret

subr:
    mov eax,1
    ret

有优化;首先你将 subr2() 内联到 main() 中得到这个:

Int main() {
    temp = subr;
    return temp();
}

Int subr() {
    return 1;
}

然后你会做一些"constant propogation"得到这个:

Int main() {
    return subr();
}

Int subr() {
    return 1;
}

然后你将 subr() 内联到 main() 得到这个:

Int main() {
    return 1;
}

那么你会得到这样的结果:

main:
    mov eax,1
    ret

请注意,main() 只是一个普通函数。通常有启动代码,链接器将其注入到可执行文件中以初始化事物(标准库、堆等),调用 main(),然后在 main() [=39 时执行 exit() =].