LINUX.ORG.RU

Как писать ассемблер рядом с Java?

 


0

2

Привет! Вопрос спецам по Java. Я хочу писать x86 ассемблерный код прямо внутри кода проекта. Но не хочу оборачивать это в JNI (даже в виде JNA). Ну или по крайней мере, не хочу делать это руками. И хочу сделать это в юзерспейсе, а не компиляторными интринсиками (пересобирать JDK - плохо). Есть ли какая-то библиотека, которая уже так делает? Кое-что гуглится, но там какой-то полный ад.

★★★★☆

Последнее исправление: stevejobs (всего исправлений: 1)

«писать x86 ассемблерный код прямо внутри кода проекта» на Java - это как раз и есть «полный ад».
Это неосуществимо в чистом виде. Пишите плагин для того же maven/gradle/whatever, что вы там используете для сборки, пишите код в отдельных файлах и обеспечивайте генерацию вспомогательного кода на их основе, а также сборку самого ассемблера.

sanwashere ★★
()
Ответ на: комментарий от Midael

на жабе пишу не из-за WORA, а потому что это удобно - хороший язык, отличный тулинг, супер поддержка в редакторах

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от sanwashere

Вот я и прошу дать ссылку на готовое решение, чтобы не нужно было делать руками

Если делать через жопу, то можно сделать

nasm -f elf64 -o my.o my.asm
gcc -shared -z noexecstack -o my.so my.o

И после этого сразу делать native-метод с именем из этого .asm.

Индексы лежат здесь: https://docs.oracle.com/.../guides/jni/spec/functions.html

Но это совершенно не так приятно и требует отдельных телодвижений, чем если было бы сделано с хорошим API на чистой Java

Кстати, в C# это легко можно делать! Достаточно превратить код в последовательность байт, потом прямо в managed коде сделать массив из этих байт, и передать его на вход Marshal.GetDelegateForFunctionPointer

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)

By design нельзя из-за оверхеда в виде виртуалки. Ты своим языком обмазываешься прилюдно, а таких вещей не знаешь.

Невозможность таких инлайнов почему-то воспринимается писателями на джаве как фича, слышал такое лично.

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

Такие инлайны ещё как возможно.

Самый простой способ, как делать это с zero overhead - это сделать компиляторную интринсику, которая будет кэпчурить вызов метода и подменять его на нативный код. Если совсем упороться, то можно попарсить .java-файл, выдернуть оттуда конструкции типа __asm(«строка с кодом») и автоматически вливать их в интринсики. Года эдак два я писал про это на ЛОРе в рамках шуточного поста «java с ассемблерными вставками».

Но одновременно этот способ самый сложный, т.к. а) требует поддерживать пересобранную версию JDK (5-20 минут сборки в зависимости от железа, нужно развести девопс-активность). б) это получается статический код, а хотелось бы динамически, типа как в libjit

Возможность таких инлайнов, скорей всего, появится в рамках проекта Valhalla, и будет выглядеть так же как в C# - собираем код асмом, кладём его в бинарь в managed памяти, берём ссылку на него как метод. Но сейчас этого нет, и разбираться в Вальгалле некогда.

В принципе, не вижу проблем чтобы сделать это и без участия гур из Вальгаллы. И надеялся, что кто-то уже всё это сделал :) Мало ли на земле добрых людей...

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 2)

Твой код и так глюкавое, тормозное, нечитаемое говно, зачем ты хочешь ещё его ухудшить?

redgremlin ★★★★★
()
Ответ на: комментарий от stevejobs

Кстати, в C# это легко можно делать! Достаточно превратить код в последовательность байт, потом прямо в managed коде сделать массив из этих байт, и передать его на вход Marshal.GetDelegateForFunctionPointer

А можно ссыль? Все что я пока видел, это кастомные костыли для инлайна IL, но не нативного асма

Midael ★★★★★
()
Ответ на: комментарий от eao197

А Стиви еще и код пишет?

Не уверен. Но если бы писал, то этот код неизбежно был бы именно таким, как я описал.

redgremlin ★★★★★
()
Ответ на: комментарий от eao197

спасибо, от твоих оскорблений у меня проясняется в голове

можно из Java звать C++ по JNI, а из C++ - уже что угодно. Есть ли какой-нибудь годный мануал, как из C++ запустить динамически сгенерённый машкод, не нарвавшись на DEP под виндой?

stevejobs ★★★★☆
() автор топика

Ты не мог бы озвучить ответ на первый же вопрос: ЗАЧЕМ? Чего добиваешься, что собираешься делать, какой выигрыш рассчитываешь получить?

I-Love-Microsoft ★★★★★
()

То есть ты хочешь, чтобы JVM динамически генерила асм-код на основе данных из джававского байт-кода, автоматически линковала его в нативную либу, и автоматически дергала через jni? Или что ты вообще хочешь?

morse ★★★★★
()
Ответ на: комментарий от stevejobs

Такие инлайны ещё как возможно.

Самый простой способ, как делать это с zero overhead - это сделать компиляторную интринсику

Видишь, как всё просто. Давай - пара вечеров, и всё готово.

tailgunner ★★★★★
()
Ответ на: комментарий от stevejobs

Сам понимаешь, что если надо патчить компилятор для таких финтов, то это уже не то пальто. Формально это новый язык, да.

Возможность таких инлайнов, скорей всего, появится в рамках проекта Valhalla, и будет выглядеть так же как в C# - собираем код асмом, кладём его в бинарь в managed памяти, берём ссылку на него как метод. Но сейчас этого нет, и разбираться в Вальгалле некогда.

В принципе, не вижу проблем чтобы сделать это и без участия гур из Вальгаллы. И надеялся, что кто-то уже всё это сделал :) Мало ли на земле добрых людей...

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

Действительность такова, что если хочется писать максимально эффективный (если необходимы ассемблерные вставки, то наверное) код, то не на джаве.

Bfgeshka ★★★★★
()
Ответ на: комментарий от stevejobs

от твоих оскорблений у меня проясняется в голове

Актитесь. Где ж вы оскорбления увидели?

Есть ли какой-нибудь годный мануал, как из C++ запустить динамически сгенерённый машкод, не нарвавшись на DEP под виндой?

Понятия не имею. Я бы начинал искать с libgccjit. Работает ли это под Win — хз.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Нет, в сисярпе зато dll/so-шки нативные легко цеплять, а в них уже может лежать сишное с ассемблерным. Но их надо тоже чем-то собирать.

Проще с этим делом у Python - C extensions вообще идеально, которые я полагаю могут получать какие-то опции на этапе установки. Наконец, для Python есть llvmpy и может еще подобные штуки - прям как надо ТС-у.

Вот иногда поражаюсь, что Python является более адекватной платформой чем жаба, а уж PySide2 (для Qt-шного GUI) так и подавно.

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

ЗАЧЕМ?

Первое, что приходит в голову -поэксплуатировать известные уязвимости.

anonymous
()
Ответ на: комментарий от I-Love-Microsoft

а многопоточность в пистон уже завезли? пишу из 2006го

anonymous
()
Ответ на: комментарий от Bfgeshka

Но ассемблерные вставки не гарантируют эффективность кода. Бывают случаи, когда вариант компилятора кажется медленнее человеческого. но на деле тесты показывают ускорение. А недостатки ассемблера очевидны — непереносимость, сложность отладки, сложность написания, устаревание кода (процессоры-то развиваются, оптимальный вариант сегодня может в разы проигрывать через пару лет за счёт новых инструкций).

redgremlin ★★★★★
()
Ответ на: комментарий от stevejobs

можно из Java звать C++ по JNI, а из C++ - уже что угодно.

Из Java можно вызвать только код, написанный на C (через JNI), но никак не С++.

Я делал DLL для использования в Java-приложении на Delphi5-7. В процедурах и функциях, написанных отдельно от классов Delphi Object Pascal, можно использовать ассемблерные вставки. FreePascal, скорее всего, тоже может быть задействован.

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 1)
Ответ на: комментарий от iZEN

но никак не С++.

Зачем ты сюда это пишешь? Ты же в этом просто ноль. Все кто мне писал - слились.

extern "C" {
SomeJavaJNIShitTypedef some_c_function(struct SomeJavaJNI *p) {
   cout << "привет" << std::endl;
}
Лол :-)

anonymous
()
Ответ на: комментарий от I-Love-Microsoft

ЗАЧЕМ?

напишу на следующей неделе отдельным постом на Хабр (на ЛОР не поместится, плюс местные модераторы уже чистили посты по причине «лор - не wiki»)

вообще имхо, для вопросов уровня тулинга вопрос «зачем» имеет посредственное значение. Причины всегда можно найти. Как будет пользоваться твоей тулой конечный пользователь - ну, это уже не твоё дело

и да, анон верно догадался про уязвимости. Уже есть готовый код, но там слишком много C++, хочется как можно больше сконвертить в жабу

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

Возможность таких инлайнов, скорей всего, появится в рамках проекта Valhalla, и будет выглядеть так же как в C# - собираем код асмом, кладём его в бинарь в managed памяти, берём ссылку на него как метод

Только это будет ни разу не инлайн.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

чем это отличается от инлайна?

гляди что можно сделать: берёшь асмовый код (или даже C++!) и пихаешь как строку.

поддержка IntelliJ IDEA дастся автоматически, она умеет распознавать строки, в которых внутри другие языки. Например, так всегда происходит с SQL и регэкспами.

если сохранишь этот текст в аннотацию (типа @Cpp(«yourcode»)), то можно будет обойтись базовыми штуками типа annotation processor. Апроцессоры отрабатывают на этапе компиляции, поэтому можно будет компилировать всё вместе - и джавакод, и всякий другой

но можно использовать Spring, и тогда хранить код можно будет где угодно, хоть в обычной строке внутри java-файла, хоть в отдельном cpp/asm файле (заюзав магию bean post processors и factory bean post processors), но это всё ещё будет статически

а можно заюзать Java Agents, и тогда можно устроить что-то типа полноценного динамического джита. Берём вызовы определённых методов и подменяем

но всё это даёт лютый оверхед, конечно. Поэтому самое ультимативное решение - это переходить на GraalVM, но не голую, придётся часть приватного апи расширить (сложно!)

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

на жабе пишу не из-за WORA, а потому что это удобно - хороший язык, отличный тулинг, супер поддержка в редакторах

Хороший язык, который неприменим для решения поставленной задачи — это плохой язык в контексте данной задачи. А тот, кто пытается решать задачу неподходящими инструментами, профнепригоден в каком угодно контексте.

Zenom ★★★
()
Ответ на: комментарий от stevejobs

ASM-вставки нативного кода в текст на языке Java можно организовать через свои аннотации времени компиляции, преобразующие аннотированные фрагменты в действия по компиляции и сборке динамической библиотеки, вызовы к которой организуются через методы-заглушки (по протоколу JNI).

iZEN ★★★★★
()
Ответ на: комментарий от stevejobs

чем это отличается от инлайна?

То есть ты не понимаешь, что такое инлайн-ассемблер, но бодро рассуждаешь о том, как его сделать. Еванге^WПродаваны такие продаваны.

Инлайн-ассемблер - это ассемблерный код, 1) выполняющийся без оверхеда на вызов функции 2) имеющий непосредственный доступ к контексту функции, в которой определен (параметры, переменные).

гляди что можно сделать: берёшь асмовый код (или даже C++!) и пихаешь как строку.

Гляди, что ты делаешь: ты неправильно используешь общепринятый термин, по невежеству или умыслу.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от Zenom

есть такая концепция (которую очень любят в Scala, например), что язык - это конструктор.

какие базовые блоки для себя соберёшь, такой у тебя язык и получится.

для того, чтобы переиначивать язык под конкретную задачу, у тебя есть инструменты: построители DSL, макросы, компиляторные интринсики, AST-процессоры типа LINQ из C#, и так далее

таким образом можно взять для себя один-единственный базовый язык, и допердоливать дополнительными блоками до конца жизни

для меня этот язык - Java.

если Java что-то не умеет - нужно поднапрячься и придумать такое расширение, которое позволит Java это уметь. Причём уметь красиво и удобно - не хуже, чем на других платформах

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от iZEN

кококо. фукнции С можно и на спп писать.


template <typename T>
class A : public SomeIface
{
   int some_iface_function() override;
}

extern "C" {

void *create_some() {return static_cast <void *> (new A <int> );}

void dispose_some(void *p) {delete static_cast <SomeIface *> (p);}

int get_some(void *p) {return static_cast <SomeIface *> (p) ->some_iface_function();}

}

anonymous
()
Ответ на: комментарий от tailgunner

имеющий непосредственный доступ к контексту функции, в которой определен (параметры, переменные).

а ещё можно оставить поехавший стек, это весело!

anonymous
()
Ответ на: комментарий от anonymous

еще веселее лезть в стек выше bsp. а если ещё менять там что-то то вообще весело как на концерте петросяна.

anonymous
()
Ответ на: комментарий от tailgunner

Ты видел что-нибудь в Java, что выполняется без оверхеда? :D Вопрос только в его размере: у интринсик он минимальный, у спринга - гигантский.

Контекст функции во всех примерах выше передаётся (разными способами). Если менять со стороны компилятора - у тебя всегда есть ссылка на текущий фрейм (что в голом хотспоте, что в граале). Если менять со стороны клиента - джава-агент знает кучу разной инфы о функции, которую собирается менять. Спринг вообще твой бин собирает из разных кусков

Если совсем уж упарываться, то можно сделать то же самое, что делает джит (бинарные шаблоны, куда ты подставляешь нужный код), но это уже явно не на пару дней

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

таким образом можно взять для себя один-единственный базовый язык, и допердоливать дополнительными блоками до конца жизни

поздравляю, ты придумал лисп. так что лучше пиши канпелятор лиспа на жаве, а не с асмом сношайся (то что ты хочешь именно так и называется)

anonymous
()
Ответ на: комментарий от stevejobs

есть такая концепция (которую очень любят в Scala, например), что язык - это конструктор.

Эта концепция именуется натягиванием совы на глобус. Смею заверить, как человек, чей основной рабочий инструмент как раз Scala, что ничем подобным разработчики языка не занимаются.

Zenom ★★★
()
Ответ на: комментарий от stevejobs

Ты видел что-нибудь в Java, что выполняется без оверхеда? :D

Практически любая конструкция Java может быть выполнена без оверхеда - если JVM догадается, как это сделать.

Контекст функции во всех примерах выше передаётся (разными способами

Стиви, у тебя с чтением как? Я же сказал - инлайн-ассемблер имеет доступ непосредственно к контексту. Не к его копии, не к ссылке - непосредственно к нему.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

а ещё можно оставить поехавший стек, это весело!

А еще можно портить значения в стековых кадрах других функций! Welcome to the party!

tailgunner ★★★★★
()
Ответ на: комментарий от vasily_pupkin

Сделай себе JNI биндинг к libtcc

Лучший комментарий.

tailgunner ★★★★★
()

опять жабка тормозит?

anonymous
()
Ответ на: комментарий от redgremlin

Ага, то-то он больше нигде не используется - ни в кодеках, ни в архиваторах, ни в криптовании.

Bfgeshka ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.