OCaml позволяет вызывать функции C из программ OCaml, пока программист следует инструкциям в главе «Взаимодействие C с OCaml» данного руководства.
При выполнении этих инструкций вызов функции C транслируется встроенным компилятором в:
movq ml_as_z_sub@GOTPCREL(%rip), %rax
call caml_c_call@PLT
(здесь набор инструкций amd64, но, глядя на другие архитектуры, схема кажется довольно единообразной).
Функция caml_c_call
в конечном итоге выполняет вычисленный переход , вызов *% rax
, но она делает много вещей до и после. Из asmrun / amd64.S:
/* Call a C function from Caml */
FUNCTION(G(caml_c_call))
.Lcaml_c_call:
/* Record lowest stack address and return address */
popq %r12
STORE_VAR(%r12, caml_last_return_address)
STORE_VAR(%rsp, caml_bottom_of_stack)
/* Make the exception handler and alloc ptr available to the C code */
STORE_VAR(%r15, caml_young_ptr)
STORE_VAR(%r14, caml_exception_pointer)
/* Call the function (address in %rax) */
call *%rax
/* Reload alloc ptr */
LOAD_VAR(caml_young_ptr, %r15)
/* Return to caller */
pushq %r12
ret
Когда кто-то хочет часто выполнять пару инструкций, которые не выделяют и не вызывают исключения, приведенное выше будет немного излишним.
Есть ли у кого-нибудь опыт вызова небольшой процедуры сборки непосредственно из OCaml, без использования заглушки caml_c_call
? Скорее всего, это связано с обманом собственного компилятора, заставляющим думать, что он вызывает функцию машинного обучения или модифицирует компилятор.
Вопрос находится в контексте библиотеки Zarith, где небольшие ассемблерные биты кода могут вычислять и возвращать большинство результатов напрямую, без необходимости проходить caml_c_call
, и переходить только к caml_c_code
для сложных аргументов, требующих выделения или исключений. См. этот файл , где приведены примеры битов сборки, которые могут выполняться напрямую.