Как изменить сборку Erlang? Доступны ли какие-либо ресурсы?
Я сомневаюсь, что кто-то может помочь с этим вопросом из-за следующего в документации компиляции Эрланга:
Обратите внимание, что формат файлов на ассемблере не задокументирован и может меняться в зависимости от выпуска - этот параметр предназначен в основном для внутренней отладки.
... но на всякий случай, здесь идет след стека истории:
- compile: 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}}.
... так что я предположил, что единственное, что необходимо для добавления вызова функции в сборку, это добавить этот кортеж... но теперь, когда я начал вводить кортеж, я вижу, что генерируемая сборка имеет некоторые дополнительные инструкции:
Без синер: 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}.).
Итак, теперь вопрос в том, есть ли какой-нибудь ресурс, который я могу использовать, чтобы понять и манипулировать сборкой, созданной компиляцией Эрланга:file/2?
Я задаю этот вопрос на всякий случай. Я сомневаюсь, что для этого есть ресурс, так как в документации четко сказано, что его нет, но мне нечего терять. Даже если бы и было, кажется, что манипулирование ассемблерным кодом будет сложнее, чем хотелось бы. Использование parse_transform/2 определенно проще, и мне удалось получить что-то похожее, чтобы работать с ним... просто пробовал разные альтернативы.
Спасибо за ваше время.
3 ответа
Единственный известный мне инструмент, использующий ассемблер луча, - HiPE, в https://github.com/erlang/otp/tree/master/lib/hipe/icode есть много примеров кода, хотя я бы не советовал делать много с этим форматом, так как он постоянно меняется.
Я не уверен, что вы пытаетесь достичь с этим, но ядро erlang может быть лучшим уровнем для манипулирования кодом. Это задокументировано (ну, во всяком случае, одна из версий, но это все же лучше, чем ничего) здесь (и есть еще только Google для ядра 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
Мне казалось, что то, что вы пытаетесь сделать, можно легко решить, манипулируя абстрактным кодом. Просто напишите модуль parse_transform, внутри которого вы можете вставить вызов функции в рассматриваемые функции.
Я написал ?funclog
на основе эрланга decorators
, см. https://github.com/nicoster/erl-decorator-pt