Assembly 函数式编程如何在汇编级别工作?
我目前的项目是制作一个小型编译器,以获得乐趣。 目前,它能够为子程序调用生成代码 我想用我的语言启用函数式编程。 但我偶然发现了一个问题,即我不知道在堆栈上传递的函数所在的代码段中标签的地址。nasm能帮我算一下吗?在其他函数式语言中如何处理这个问题Assembly 函数式编程如何在汇编级别工作?,assembly,x86,compiler-construction,Assembly,X86,Compiler Construction,我目前的项目是制作一个小型编译器,以获得乐趣。 目前,它能够为子程序调用生成代码 我想用我的语言启用函数式编程。 但我偶然发现了一个问题,即我不知道在堆栈上传递的函数所在的代码段中标签的地址。nasm能帮我算一下吗?在其他函数式语言中如何处理这个问题 Int main(){subr2(subr);} Int subr2(Int() myfn){return myfn();} Int subr(){return 1;} 这个荒谬的代码将如何翻译? 我试着做一个我能做的最小的例子 我看到的问题是,
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;
这:
在没有任何优化的情况下,假设调用约定不可怕,则会变成:
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;
}
Int main() {
return subr();
}
Int subr() {
return 1;
}
Int main() {
return 1;
}
然后你要做一些持续的传播来得到这个:
Int main() {
temp = subr;
return temp();
}
Int subr() {
return 1;
}
Int main() {
return subr();
}
Int subr() {
return 1;
}
Int main() {
return 1;
}
然后将subr内联到main中,以获得以下结果:
Int main() {
temp = subr;
return temp();
}
Int subr() {
return 1;
}
Int main() {
return subr();
}
Int subr() {
return 1;
}
Int main() {
return 1;
}
然后你会得到这样的结果:
main:
mov eax,1
ret
注意main只是一个普通函数。通常,链接器会将启动代码注入到可执行文件中,该文件初始化标准库、堆等,调用main,然后在main返回时退出。不确定问题出在哪里?填充偏移量不是你的工作,汇编程序和链接程序会帮你完成。您只使用标签。@Jester我不能使用标签,因为我想传递对堆栈上函数的引用。我不确定你是否可以把标签推到堆栈上?当然可以。你为什么不能?杰斯特你刚刚解决了我的问题!谢谢:虽然您的具体问题已经解决了,但应该注意的是,在函数语言中传递一级函数比传递函数的地址更重要:闭包;不需要先推imm32/pop eax,然后推jmp eax。此外,您还可以使用call subr为您推送回信地址。所有这些都不演示将函数指针传递给另一个函数。您可以通过使用标签来实现这一点;标签地址是链接时间常数,因此链接器可以将它们填充到绝对mov reg、标签或相对jmp标签引用中。或者,如果无法内联(例如,函数指针不是编译时常数),则您可以优化调用eax/ret tailcall到subr2中的jmp eax中。