[Recommended] Three methods to obtain the aarch64 version of libv8_monolith.a static library

Foreword

Not long ago, in order to get the OpenRASP for linux aarch64 version, the most critical thing in the middle is Chromium’s open source v8 engine (commonly known as libv8), which is introduced in the form of a static library (libv8_monolith.a). The official precompiled version is 7.8.279.19, relatively old. I tried to compile this version from V8 official source code, but it always ran OOM (I don’t know if it was a problem with the compilation environment), so I gave up with tears~~~
The following is the error message during the process:

mvn install

OOM

gdb ../build64/java/libopenrasp_v8_java.so core.xxxxx # xxxxx is the process number of coredump

Call Stack

Later, after repeated attempts (the articles on the Internet were really short, but in the end they all pointed to failure, asking for help with GPT was basically nonsense, which made me take many detours), I found the 8.6.395.17 version. hello-world can run normally, so the follow-up work of OpenRASP update will be carried out based on this version.
This article will talk about the three methods of obtaining the libv8_monolith.a static library that I have explored in the past three weeks for readers’ reference.

Method 1: Use Libv8 official code

  • Advantages: Native code, clean; the generated library is small in size and easy to configure parameters.
  • Disadvantages: It requires a ladder to access, the tool chain is huge, and the compilation environment is very slow to set up.
  • Reference: https://github.com/tanjelly/openrasp-v8/blob/master/vendors/build-libv8.sh

PS: I didn’t know there was this script in the project at first, so I took a lot of detours! ! !

Installing the system

  • Ubuntu22.04 X86_64

Install necessary components

sed -i 's#/archive.ubuntu.com#/mirrors.ustc.edu.cn#g' /etc/apt/sources.list
sed -i 's#/security.ubuntu.com#/mirrors.ustc.edu.cn#g' /etc/apt/sources.list

apt-get update
apt-get upgrade
apt-get install vim git python2 python3 python3-pip ninja-build clang-14
apt-get install pkg-config libglib2.0-dev
ln -s /usr/bin/python2 /usr/bin/python
export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/share/pkgconfig:/usr/lib/$(uname -p)-linux-gnu/pkgconfig

Pull and compile libv8 related code

cd /opt/
# Pull compilation tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=/opt/depot_tools:$PATH

# Initialize the compilation environment (if there is an error, it needs to be handled according to the error)
python3 /opt/depot_tools/gclient.py

# Pull v8 code
fetch v8

# Pull related dependencies (long wait...)
cd v8
git checkout 8.6.395.17
gclient sync -v
# Or execute python3 /opt/depot_tools/gclient.py sync -v

Install aarch64 compilation environment

cd /opt/v8/
python build/linux/sysroot_scripts/install-sysroot.py --arch=arm64

Build

cd /opt/v8/

# Build configuration
mkdir -p out/arm64.release
cat > out/arm64.release/args.gn <<EOF
is_debug = false
target_cpu = "arm64"
symbol_level = 0
is_component_build = false
treat_warnings_as_errors = false
use_custom_libcxx = false
libcxx_abi_unstable = false
v8_embedder_string = " <OpenRASP>"
v8_monolithic = true
v8_enable_i18n_support = false
v8_use_snapshot = true
v8_use_external_startup_data = false
v8_enable_shared_ro_heap = true
EOF

# Generate build-related files (the libcxx_abi_unstable problem may be prompted during the process, ignore it directly)
gn gen out/arm64.release

# Build (16 is the number of CPUs)
/usr/bin/ninja -C out/arm64.release -j 16 v8_monolith

#The final generated library file (size is about 40M)
out/arm64.release/obj/libv8_monolith.a

The generation method of other versions of libv8_monolith.a is basically the same as the aarch64 version. You only need to modify the target_cpu parameter in the args.gn file to x64 (compilation is successful) ) or x86 (cross compilation failed, you may need to compile in the i386 system environment).

Method 2: Use Nodejs official code

  • Advantages: You can use the system’s default compilation environment, saving a lot of time in pulling the tool chain.
  • Disadvantages: It is not easy to customize. I have not thoroughly studied how to adjust parameters. The final generated file is also larger than [Method 1] (about 70M +)
  • Reference: https://github.com/rubyjs/libv8-node/blob/master/libexec/build-libv8

Install and start the system

  • CentOS 7.9 Aarch64

Install necessary components

yum update -y
yum -y install cmake git wget vim python2 centos-release-scl
yum makecache

Install compilation tools

yum -y install devtoolset-10
scl enable devtoolset-10 bash

Pull Nodejs code

wget https://nodejs.org/dist/v15.14.0/node-v15.14.0.tar.gz
tar -xf node-v15.14.0.tar.xz

Compile Nodejs

cd node-v15.10.0/
CPUS=`cat /proc/cpuinfo | grep processor | wc -l`

#Configuration
./configure --openssl-no-asm --without-npm --shared --without-intl --without-siphash
sed -i "56i \ 'v8_embedder_string': ' <OpenRASP>'," config.gypi

# compile
make -j$CPUS

Packaging libv8_monolith.a

First create a script build-monolith.sh containing the following content in the nodejs source code root directory (refer to the node-v8-monolith project)

#!/bin/sh

BASEDIR=$(pwd)
BUILDTYPE=${BUILDTYPE:-Release}

cd out/${BUILDTYPE}/obj.target

if [ "$(uname)" = "SunOS" ]; then
  /usr/xpg4/bin/find . -path "**/*v8*/**/*.o" | xargs ar cqs libv8_monolith.a
  /usr/xpg4/bin/find . -path "**/*icu*/**/*.o" | xargs ar cqs libv8_monolith.a
elif [ "$(uname)" = "Linux" ]; then
  for lib in `find . -path './tools/v8_gypfiles/*.a'`;
    do ar -t $lib | xargs ar -q libv8_monolith.a;
  done;
  for lib in `find . -path './tools/icu/*.a'`;
    do ar -t $lib | xargs ar -q libv8_monolith.a;
  done;
else
  echo "Unsupported Platform"
  exit
fi

mv libv8_monolith.a $BASEDIR/out/${BUILDTYPE}

Then execute the script to generate the file:

bash ./build-monolith.sh

# Generated library file location
out/Release/libv8_monolith.a

Method 3: Use libv8-node precompiled library

  • Advantages: This method is the most trouble-free and saves a lot of time fussing with the libv8 library.
  • Disadvantages: The file is a bit large and cannot be customized.

Download libv8-node

# I originally wanted to find a version consistent with method 2, but found that it was not officially provided.
wget https://rubygems.org/downloads/libv8-node-15.14.0.1-aarch64-linux.gem

Use 7zip to extract the following files from the downloaded package:

data.tar.gz/data.tar/vendor/v8/include
data.tar.gz/data.tar/vendor/v8/out.gn/libv8/obj/libv8_monolith.a

Summary

From a comprehensive comparison, it is better to use [Method 1] if conditions permit among the three methods. If you want to save time, [Method 3] is a good choice. [Method 2] Suitable for students who have a certain foundation in parameter adjustment.

Reference

1: https://github.com/sqreen/node-v8-monolith
2: https://github.com/tanjelly/openrasp-v8
3: https://v8.dev/docs/compile-arm64
4: https://rubygems.org/gems/libv8-node/versions/15.14.0.1-aarch64-linux
5: https://nodejs.org/