Как работает функциональное программирование на уровне сборки? - PullRequest
0 голосов
/ 25 сентября 2019

Мой текущий проект - сделать небольшой компилятор для развлечения.В настоящее время он может генерировать код для вызовов подпрограмм.

Я хочу включить функциональное программирование на моем языке.Но я наткнулся на проблему, заключающуюся в том, что я не знаю адрес метки (в сегменте кода), где находится функция, которую я передаю в стек.может насм рассчитать это для меня?как это обрабатывается в других функциональных языках?

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

Как будет переводиться этот (бессмысленный) код?Я попытался сделать наименьший пример из всех возможных.

Проблема, которую я вижу, состоит в том, что вы не знаете смещения в сегменте кода метки (который удаляется ассемблером?) Как компилятор, который only компилируется до уровня сборки.

Как это можно решить без особых накладных расходов?

Спасибо за ваше время!

РЕДАКТИРОВАТЬ: @Jester указал, что вы можете помещать метки в стек в сборке

Ответы [ 2 ]

2 голосов
/ 25 сентября 2019

Это:

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;
}

Затем вы бы сделали "постоянное распространение", чтобы получить это:

Int main() {
    return subr();
}

Int subr() {
    return 1;
}

Затемвы бы вставили subr() в main(), чтобы получить это:

Int main() {
    return 1;
}

Затем вы получите следующее:

main:
    mov eax,1
    ret

Обратите внимание, что main() это простонормальная функция.Обычно есть стартовый код, который компоновщик вставляет в исполняемый файл, который инициализирует вещи (стандартная библиотека, куча и т. Д.), Вызывает main(), а затем выполняет exit(), если main() возвращает.

0 голосов
/ 25 сентября 2019

@ У Шута было решение.Действительно, вы можете помещать метки в стек в сборке.

Пример кода:

   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;
...