#assembly #erlang
#сборка #erlang
Вопрос:
Я сомневаюсь, что кто-нибудь может помочь с этим вопросом из-за следующего в документации по компиляции Erlang:
Обратите внимание, что формат файлов ассемблера не документирован и может меняться между выпусками — этот параметр в основном предназначен для внутренней отладки.
… но на всякий случай, здесь идет трассировка стека истории:
- скомпилируйте:file/2 с помощью [‘S’] для генерации кода сборки
- Прочитайте файл .S и создайте структуру данных ключ-значение, в которой ключ — это кортежи «функции» в файле .S, а значение — тело функции, то есть инструкции по сборке, которые реализуют функцию.
- Измените структуру данных, добавив сборку для выполнения вызова внешней функции в определенных функциях.
- сбой…
К сожалению, я просто быстро просмотрел файлы .S, созданные при компиляции модуля, содержащего следующую функцию, с первым выражением в функции и без него, закомментировано:
spawn_worker(Which) ->
%syner:sync_pt(),
case Which of
?NAIVE -> spawn(err1, naive_worker_loop, [])
end.
Когда я это сделал, я подумал, что единственное, что изменилось, это кортеж:
{call_ext,0,{extfunc,syner,sync_pt,0}}.
… поэтому я предположил, что единственное, что необходимо для внедрения вызова функции в сборку, — это добавить этот кортеж… но теперь, когда я фактически ввел кортеж… Я вижу, что сгенерированная сборка содержит несколько дополнительных инструкций:
Без syner:sync_pt():
{function, spawn_worker, 1, 4}.
{label,3}.
{func_info,{atom,err1},{atom,spawn_worker},1}.
{label,4}.
{test,is_eq_exact,{f,5},[{x,0},{atom,naive}]}.
{move,{atom,naive_worker_loop},{x,1}}.
{move,nil,{x,2}}.
{move,{atom,err1},{x,0}}.
{call_ext_only,3,{extfunc,erlang,spawn,3}}.
{label,5}.
{case_end,{x,0}}.
С помощью syner:sync_pt():
{function, spawn_worker, 1, 4}.
{label,3}.
{func_info,{atom,err1},{atom,spawn_worker},1}.
{label,4}.
{allocate,1,1}.
{move,{x,0},{y,0}}.
{call_ext,0,{extfunc,syner,sync_pt,0}}.
{test,is_eq_exact,{f,5},[{y,0},{atom,naive}]}.
{move,{atom,naive_worker_loop},{x,1}}.
{move,nil,{x,2}}.
{move,{atom,err1},{x,0}}.
{call_ext_last,3,{extfunc,erlang,spawn,3},1}.
{label,5}.
{case_end,{y,0}}.
Я не могу просто сделать вывод, что добавление чего-то вроде:
{allocate,1,1}.
{move,{x,0},{y,0}}.
{call_ext,0,{extfunc,syner,sync_pt,0}}.
для каждой функции, в которую я хочу ввести вызов внешней функции, это поможет.
- потому что я не уверен, применим ли этот код сборки ко всем функциям, в которые я хочу внедрить (например, всегда ли {allocate,1,1} в порядке)
- потому что, если вы внимательно посмотрите на остальную часть сборки, она немного изменится (например, {call_ext_only,3,{extfunc,erlang,spawn,3}}. изменения в {call_ext_last,3,{extfunc,erlang,spawn,3},1} .).
Итак, теперь вопрос в том, есть ли какой-либо ресурс, который я могу использовать для понимания и управления сборкой, созданной компиляцией Erlang:file/ 2?
Я задаю этот вопрос на всякий случай. Я сомневаюсь, что для этого есть ресурс, поскольку в документации четко указано, что его нет, но, думаю, мне нечего терять. Даже если бы это было так, похоже, что манипулирование ассемблерным кодом будет сложнее, чем хотелось бы. Использование parse_transform/2 определенно проще, и мне удалось получить что-то похожее для работы с ним … просто пробуя разные альтернативы.
Спасибо за ваше время.
Комментарии:
1. (Информация из тестирования, а не из источников чтения.)
{allocate,1,1}
выделяет одно место в стеке y. Стек x — это «обычный» стек, регистры. Стек y является вспомогательным стеком.{move,{x,0},{y,0}}
перемещает самый верхний x в самый нижний y (по крайней мере, думаю, что они растут в обратном направлении). Мой тестовый файл: pastebin.com/R21ZJ29Q . Его результат: pastebin.com/jULjMCV0 .2. Спасибо за помощь, Кей. Похоже, что выяснение сборки займет у меня слишком много времени, поэтому я не планирую ее расшифровывать. Приветствия.
Ответ №1:
Единственный инструмент, который я знаю, который использует beam asm, — это HiPE, есть много примеров кода и тому подобное в https://github.com/erlang/otp/tree/master/lib/hipe/icode , хотя я бы не рекомендовал много работать с этим форматом, поскольку он постоянно меняется.
Комментарии:
1. Точка взята. Работа с представлением сборки вызывает проблемы. Приветствия.
Ответ №2:
Я не уверен, чего вы пытаетесь достичь с помощью этого, но core erlang может быть лучшим уровнем для выполнения манипуляций с кодом. Это задокументировано (во всяком случае, одна его версия, но это все же лучше, чем ничего) здесь (и есть еще только Google для core erlang):
Для компиляции в ядро erlang и из него используйте опции ‘to_core’ и ‘from_core’ (к сожалению, недокументированные):
c(my_module, to_core). %%this generates my_module.core
c(my_module, from_core). %%this loads my_module.core
Комментарии:
1. Я думаю, что core erlang — это то, что используется lfe ( github.com/rvirding/lfe ), вы могли бы найти там какую-нибудь полезную информацию
2. хм, я быстро прочитал эту статью, но еще не пробовал использовать core Erlang. Я думаю, я рассмотрю это немного подробнее. Спасибо за указатель TamasNagy.
3. lfe использует ядро erlang да. Круто, тем больше причин проверить это. Спасибо Лукасу.
Ответ №3:
Мне показалось, что то, что вы пытаетесь сделать, можно легко решить, манипулируя абстрактным кодом. Просто напишите модуль parse_transform, в который вы могли бы вставить вызов функции в рассматриваемые функции.
Я написал на ?funclog
основе erlang decorators
. см https://github.com/nicoster/erl-decorator-pt#funclog