Библиотека hsdis удобна для преобразования листинга машинного кода, создаваемого JIT-компилятором, в читаемый ассемблерный код. Просмотр ассемблерных инструкций может пригодиться для проверки и отладки какого-то критического участка кода, который, например, чувствителен к latency.
При компиляции JIT-компилятор производит множество оптимизаций, и вывод ассемблерного кода помогает проверить, насколько эффективный код сгенерировал JIT-компилятор, посмотреть, были ли ожидаемые оптимизации сделаны, или что-то помешало JIT-компилятору их сделать.
Библиотека hsdis не распространяется отдельно. Oracle запрещает раздавать файл отдельно от jdk и предлагает всем, кому нужна библиотека компилировать ее самостоятельно. Да и скачивать файл .dll или .so с какого-нибудь мутного сайта, а потом запускать его на своей машине - несколько стрёмно. Мало-ли каких хитрецов под видом hsdis могут подсунуть вам для скачивания троян или вирус.
Исходники hsdis поставляются вместе с исходниками JDK, и расположены в папке jdk/src/utils/hsdis/ исходников. По просторам Интернета разбросано множество инструкций, как собрать hsdis. Но все эти инструкции: а) устарели (относятся к версиям Java 8) б) запутаны и неполные. Я сам пытался по этим инструкциям собрать hsdis для Windows на своей машине и пришлось попотеть и потанцевать с бубном, чтобы получить нужный результат.
В данной статье я пытаюсь описать процесс сборки hsdis для Windows и для Linux, чтобы помочь вам сэкономить время и обойти подводные камни. Я не делал кросс-компиляцию, т.е. не собирал на Windows библиотеку hsdis для Linux. Для сборки hsdis под каждую платформу я использовать "родную" платформу. Может быть шаги, описанные ниже излишне сложны, но именно эти шаги привели меня к результату. Если есть какой-то более короткий путь к цели, пишите в комментариях.
Сборка hsdis для Windows 64-bit
Для сборки hsdis для Windows я использовал:
Cygwin - для запуска всех утилит сборки
исходники binutils - которые надо собрать под Windows платформу
Microsoft Visual Studio - для предоставления microsoft tool chain для сборки под платформу Windows
Проверьте, что на вашей Windows машине установлена Java не ниже Java 17 с прописанным %JAVA_HOME%. Это будет так называемый Boot JDK, который по какой-то причине нужен сборщику.
Устанавливаем Cygwin на Windows машине. При выборе пакетов Cygwin выбираем:
gcc-core
mingw64 - для сборки 64-битной версии бинарников
zip / unzip
make, autoconf
важно: не надо выбирать binutils из пакета Cygwin. Он не подойдет для сборки hsdis. binutils мы будем собирать из исходников
При установке Cygwin в cygwin-папке создается иерархия Unix-like файловой системы. В папке /home будет расположена ваша home-директория. Запомните, где она расположена в Windows, например, D:\tools\cygwin64\home\<yourname>.
Устанавливаем Microsoft Visual Studio. На сайте Visual Stuido есть бесплатная версия - Community Edition, которой вполне достаточно для нашей цели. При выборе пакета утилит, выбирайте "C++ Desktop development". MVS можно устанавливать куда угодно. При сборке cygwin найдет, где он расположен.
Скачиваем исходники binutils. В инструкциях рекомендуется версия 2.37. Исходники можно взять с сайта binutils. Скачайте исходники 2.37 и распакуйте их в папку binutils-2.37 в папке D:\tools\cygwin64\home\<yourname>\.
Скачиваем исходники jdk путем простого клонирования git-репозитория с GitHub. Я клонировал master репозиторий, то есть текущую ветку разработки, а она сейчас уже находится на стадии Java 19!
Копируем исходники в home-папку. У вас получится такой путь: /home/<yourname>/jdk/, и в этой папке будут все файлы исходников jdk первого уровня. Запомните, запуск всех команд будет производиться из этой папки: /home/<yourname>/jdk/.
Запускаем терминал Cygwin64 Terminal. Переходим в папку /home/<yourname>/jdk/. В командной строке набираем первую команду, которая настроит среду сборки:
# ./configure --with-hsdis=binutils --with-binutils-src=/home/<yourname>/binutils-2.37/
./configure - это конфигурационный скрипт, который расположен в корневой папке исхдников jdk. Параметр --with-hsdis=binutils сообщает конфигуратору, что мы будем собирать библиотеку hsdis с помощью binutils. Параметр --with-binutils-src=/home/<yourname>/binutils-2.37/ сообщает конфигуратору, что binutils надо собрать из исходников, и мы указываем, где эти исходники находятся.
Если все прошло хорошо, конфигуратор найдет все компоненты, найдет исходники binutils, скомпилирует их выдаст в конце такой баннер:
====================================================
A new configuration has been successfully created in
/home/<yourname>/jdk/build/windows-x86_64-server-release
using configure arguments '--with-hsdis=binutils --with-binutils-src=/home/<yourname>/binutils-2.37/'.
После этого в командной строке надо набрать:
# make build-hsdis CONF=windows-x86_64-server-release
Если все прошло хорошо, то выйдет такой баннер:
Building target 'build-hsdis' in configuration 'windows-x86_64-server-release'
Finished building target 'build-hsdis' in configuration 'windows-x86_64-server-release'
После чего, надо набрать:
# make install-hsdis CONF=windows-x86_64-server-release
и вы увидите такой баннер:
Building target 'install-hsdis' in configuration 'windows-x86_64-server-release'
Finished building target 'install-hsdis' in configuration 'windows-x86_64-server-release'
а в папке D:\tools\cygwin64\home\<yourname>\jdk\build\windows-x86_64-server-release\jdk\bin\ будет уютненько сидеть файл под названием hsdis-amd64.dll. Это файл для JDK для Windows 64-bit. Поздравляю, вы стали счастливым обладателем библиотеки hsdis!
Поместите hsdis-amd64.dll в папку %JAVA_HOME%\bin, запустите Java программу в параметрами, включающими дизассемблирование, и убедитесь, что вы видите на экране ассемблерный мнемо-код.
Что может пойти не так
вы не установили все требуемые утилиты cygwin
вы не установили все требуемые утилиты microsoft tool chain
вы неправильно прописали пути в командах сборки
вы не из того каталога запускали команды сборки
В любом из указанных случаев скрипт ./configure завершится с ошибкой и в конце может подсказать, чего ему не хватает.
Сборка hsdis для Linux
В виду остутствия Linux-машины под рукой, для сборки hsdis я запускал Linux в виртуальной машине VirtualBox. Дело значительно упрощается если для этой цели используется менеджер виртуальных машин Vagrant.
Для сборки hsdis для Linux я использовал:
Oracle VirtualBox 6.1.30
Vagrant 2.2.19
вариант виртуальной машины java-spring из моего репозитория виртуальных машин для Vagrant. Spring, Gradle, Maven вообще не нужен для сборки, просто данная виртуальная машина оказалась ближе по нужным настройкам.
сборка производилась на дистрибутиве almalinux/8 ver. 8.5.20211208, который является эквивалентом CentOS 8
обязательно нужно присутствие в виртуальной машине Java JDK версии не ниже 17-ой. Это будет так называемый Boot JDK, который по какой-то причине нужен сборщику.
Запускаем виртуальную машину java-spring с помощью Vagrant:
# vagrant up
Vagrant скачает образ almalinux/8 и настроит Linux внутри виртуальной машины с нужными пакетами (git, make, autoconf, zip/unzip, jdk17). Подключаемся к виртуальной машине:
# vagrant ssh
С этого шага нет никакой разницы, работаем мы на Linux в виртуальной машине или на родном Linux.
Скачиваем исходники jdk путем простого клонирования git-репозитория с GitHub в home-папку. У вас получится такой путь: /home/<yourname>/jdk/, и в этой папке будут все файлы исходников jdk первого уровня. Запомните, запуск всех команд будет производиться из этой папки: /home/<yourname>/jdk/. Я клонировал master-ветку репозитория, то есть текущую ветку разработки, а она сейчас уже находится на стадии Java 19!
Добавить еще пару пакетов:
binutils (возможно, уже есть) и binutils-devel, X11 development libraries, cups-devel, fontconfig-devel, alsa-lib-devel
установить комплект разработки (компиляторы, линкеры и проч.) groupinstall Development Tools (в CentOS это делается командой: sudo yum groupinstall "Development Tools")
Все вышеперечисленное нужно для сборки всего JDK. Несмотря на то, что нам нужно собрать лишь hsdis, конфигуратор сборки все равно потребует наличие этих пакетов. Причем, конфигуратор сам будет подсказывать, чего ему не хватает.
Из папки /home/<yourname>/jdk/ запускаем конфигуратор сборки:
# ./configure --with-hsdis=binutils --with-binutils=system --host=x86_64-linux
./configure - это конфигурационный скрипт, который расположен в корневой папке исходников jdk. Параметр --with-hsdis=binutils сообщает конфигуратору, что мы будем собирать библиотеку hsdis с помощью binutils. Параметр --with-binutils=system сообщает конфигуратору, что binutils уже присутствует в системе. Параметр --host=x86_64-linux сообщает конфигуратору, что мы будем собирать hsdis под 64-битный Linux для PC-платформы.
Если все прошло хорошо, конфигуратор найдет все компоненты и выдаст в конце такой баннер:
====================================================
The existing configuration has been successfully updated in
/vagrant/projects/jdk/build/linux-x86_64-server-release
using configure arguments '--with-hsdis=binutils --with-binutils=system --host=x86_64-linux'.
После этого в командной строке надо набрать:
# make build-hsdis
Если все прошло хорошо, то выйдет такой баннер:
Building target 'build-hsdis' in configuration 'linux-x86_64-server-release'
Finished building target 'build-hsdis' in configuration 'linux-x86_64-server-release'
После чего, надо набрать:
# make install-hsdis
и вы увидите такой баннер:
Building target 'install-hsdis' in configuration 'linux-x86_64-server-release'
NOTE: The resulting build might not be redistributable. Seek legal advice before distibuting.
Finished building target 'install-hsdis' in configuration 'linux-x86_64-server-release'
а в папке /home/<yourname>/jdk/build/linux-x86_64-server-release/jdk/lib будет уютненько сидеть файл под названием hsdis-amd64.so. Это файл для JDK для Linux 64-bit. Поздравляю, вы стали счастливым обладателем библиотеки hsdis!
Что может пойти не так
вы не установили все требуемые утилиты
вы не из того каталога запускали команды сборки
В любом из указанных случаев скрипт ./configure завершится с ошибкой и в конце может подсказать, чего ему не хватает.
Выводы
Сборка hsdis тяжела для тех, кто идет по кроличьей норе первыми. В данной статье я "протоптал" для вас дорожку и развесил метки. Пишите в комментариях, о своих результатах сборки и на какие подводные камни напоролись вы.
Happy compiling!