So you want your own little javascript framework for your favorite ARM device? Us too… OK, here we go.
Getting V8 to compile is not a trivial issue because V8 actually writes its own assembly during operation. Remember, V8 at its core is a JIT compiler for Javascript.
ARM arch? Figure out what you have.
Chances are you are cross-compiling V8 with your target as ARM. If you are, you need to find out what kind of hardware you have; specifically what type of floating point your hardware can do and do you support VFP and VFP3. If you already have Linux up on your hardware, /proc will reveal some good information. Check out the Features line. If you don’t see vfpv3 you don’t want the vfp3 options for V8. And if you don’t see vfp and neon, then you want armeabi=soft (not even softfp, which is using hardware instructions).
root@freescale /proc$ cat /proc/cpuinfo Processor : ARM926EJ-S rev 5 (v5l) BogoMIPS : 226.09 Features : swp half thumb fastmult edsp java NOTE: MISSING: 'vfp' CPU implementer : 0x41 CPU architecture: 5TEJ CPU variant : 0x0 CPU part : 0x926 CPU revision : 5 Hardware : Freescale MX28EVK board Revision : 0000 Serial : 0000000000000000
Without Snapshot
First, get V8 cross compiling without snaphost enabled. Snapshots enable faster start of a V8 instance since it will have a pre-compiled set of standard data structures and functions. But its not necessary for functionality.
x86_64: If running uname -f gives you x86_64, your are on 64-bit linux. You need to switch to a 32-bit install to get this to cross compile right now. This is a limitation with V8′s code with tests to make sure you are cross compiling from ia32. I’ll update this if I can figure out how to cross compile on x64.
Here is a cross-compile script I used:
#!/bin/sh CROSS_BASE=/opt/freescale/usr/local/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi PREFIX_BIN=$CROSS_BASE/bin/arm-fsl-linux-gnueabi export TOOL_PREFIX=$PREFIX_BIN export CXX=$TOOL_PREFIX-g++ export AR=$TOOL_PREFIX-ar export RANLIB=$TOOL_PREFIX-ranlib export CC=$TOOL_PREFIX-gcc export LD=$TOOL_PREFIX-ld export CCFLAGS="-march=armv5te -mtune=arm926ej-s -mno-thumb-interwork" # -march=armv5te -mtune=arm926ej-s -mfloat-abi=softfp #export ARM_TARGET_LIB=$CTOOLS_LIB scons wordsize=32 snapshot=off arch=arm vfp3=off armeabi=soft sample=shell
I did not need to use the ARM_TARGET_LIB var, and frankly could not find anywhere where it was used in the compile. For more information, see Google’s cross-compiling guide for V8. On successful build, you should have an executable called shell. Since we chose not to build V8 as a shared library for now, you can just copy this executable over to the dev hardware and test.
Step by Step
Run the executable…
root@freescale ~$ ./shell V8 version 3.8.7.1 [sample shell] > var num=3.3; > print(num*3.3); 10.889999999999999 > quit();
If it fails, go back turn most options down/off. Then enable them one at time in an effort to find which feature is breaking the execution. Stuff to consider:
- GCC switches: -march=XXX, -mtune=XXX, -mno-thumb-interwork
- V8 scons options: vfp3=off/on, armeabi=off/on
- V8 scons snapshot=off - Later try to move to snapshot=on
Also, make sure you do a scons –clean (that’s a dash-dash) to cleanup objects when rebuilding.
Errors?
root@freescale ~$ ./shell Illegal instruction
My first builds didn’t work right as I did not have the floating point switches set correctly. An illegal instruction is likely caused by some assembly that your processor does not support. But let’s use gdb (if your dev hardware has it) to quickly find out.
root@freescal ~$ gdb ./shell (gdb) layout split (gdb) r (gdb) bt lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq x x x x x x x [ No Source Available ] x x x x x mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq >x0x78680 <_ZN2v88internal4HeapC1Ev+216> vldr d7, [pc, #424] ; 0x78830 <_x x0x78684 <_ZN2v88internal4HeapC1Ev+220> mov r3, #5242880 ; 0x500000 x x0x78688 <_ZN2v88internal4HeapC1Ev+224> add r8, r4, #1392 ; 0x570 x x0x7868c <_ZN2v88internal4HeapC1Ev+228> add r8, r8, #4 ; 0x4 x x0x78690 <_ZN2v88internal4HeapC1Ev+232> str r3, [r4, #392] x x0x78694 <_ZN2v88internal4HeapC1Ev+236> mvn r3, #-2147483648 ; 0xx mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq multi-thre Thread 1073867 In: v8::internal::Heap::Heap Line: ?? PC: 0x78680 #1 0x000b26fc in v8::internal::Isolate::Isolate () #2 0x000b2c10 in v8::internal::Isolate::EnsureDefaultIsolate () #3 0x000b2c8c in global constructors keyed to _ZN2v88internal8ThreadId18highest _thread_id_E () #4 0x002831c4 in __libc_csu_init () #5 0x401bf430 in __libc_start_main () from /lib/libc.so.6 #6 0x0000a254 in _start () (gdb)
The top assembly instruction is the culprit. vldr is an ARM assembly instruction for floating point. My hardware does not support this at all, so it needs complete soft-float, which is the armeabi=soft option handed to scons for V8. You can do a similar test if necessary to determine the cause of the crash.
Snapshots
Snapshots will make initial startup of V8′s instance faster. You will notice you can simply add snapshot=on to you scons command. But doing that in your cross-compile script will results in:
... obj/release/version.o obj/release/zone.o obj/release/snapshot-empty.o -lpthread obj/release/mksnapshot obj/release/snapshot.cc --logfile "/home/ed/v8/v8-src/obj/release/snapshot.log" --log-snapshot-positions /bin/bash: obj/release/mksnapshot: cannot execute binary file scons: *** [obj/release/snapshot.cc] Error 126 scons: building terminated because of errors.
This is because mksnapshot is a ARM binary, and that’s not what we need. Instead you need to build V8 once with an ARM simulator which will generate ARM code, with a x86 binary. Then this will be used to generate the snapshot to build the ARM binary with snapshot enabled.
Below is a full script which does both. This is built off Google’s information located here, but with a few minor changes.
Notice that CCFLAGS now has the -lstdc++ library tacked on. For some reason, during this two stage build, with two different build directories, libstdc++ was not being linked in. Not sure why, and your mileage will likely vary. My result was an error such as:
... undefined reference to `__cxa_pure_virtual'
Which indicates you don’t have the libstdc++ lib. Also, make sure you set the vpf3= and armeabi= options correctly when building the simulator as well, or otherwise your startup will see an Illegal Instruction again. Without snapshot the startup code is compiled when V8 is run on the target, and with snapshots its pre-stored from simulator’s output. So those options handed to scons for the simulator must be essentially the same as when cross-compiling with out snapshots.
The full script:
#!/bin/bash
V8DIR=..
function print_usage() {
echo "$0 [ with-snapshot ]"
exit
}
# some ugly option processing...
if [ $# -gt 1 ]; then
print_usage
fi
if [ $# -gt 0 ]; then
echo "Here"
if [ "$1" == "with-snapshot" ]; then
SNAPSHOT="1"
else
print_usage
fi
fi
if [ ! -z $SNAPSHOT ]; then
if [ ! -d "host" ]; then
echo "Making ./host"
mkdir host
fi
if [ ! -d "target" ]; then
echo "Making ./target"
mkdir target
fi
echo "Building simulator..."
cd host
scons -Y$V8DIR simulator=arm vfp3=off armeabi=soft snapshot=on
mv obj/release/snapshot.cc $V8DIR/src/snapshot.cc
cd ..
fi
CROSS_BASE=/opt/freescale/usr/local/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi
PREFIX_BIN=$CROSS_BASE/bin/arm-fsl-linux-gnueabi
CSTOOLS_LIB=/opt/ltib/rootfs/lib
CSTOOLS_USR_LIB=/opt/ltib/rootfs/usr/lib
export TOOL_PREFIX=$PREFIX_BIN
export CXX=$TOOL_PREFIX-g++
export AR=$TOOL_PREFIX-ar
export RANLIB=$TOOL_PREFIX-ranlib
export CC=$TOOL_PREFIX-gcc
export LD=$TOOL_PREFIX-ld
export CCFLAGS="-march=armv5te -mtune=arm926ej-s -mno-thumb-interwork -lstdc++"
# -march=armv5te -mtune=arm926ej-s -mfloat-abi=softfp
export ARM_TARGET_LIB=$CTOOLS_LIB
if [ ! -z $SNAPSHOT ]; then
cd target
echo "Building for target..."
scons -Y$V8DIR wordsize=32 snapshot=nobuild arch=arm vfp3=off armeabi=soft sample=shell
rm $V8DIR/src/snapshot.cc
cd ..
else
scons wordsize=32 snapshot=off arch=arm vfp3=off armeabi=soft sample=shell
fi
Run as
./setup-cross.sh with-snapshot
for building with a snapshot. Your finished executable is in ./target
I just want to thank you. I’ve been off and on trying to compile google V8 and shell for about a week, and this post put it together. This script built it using the compiler from timesys.
#!/bin/sh
export TOOL_PREFIX=/armdev/G20/factory/build_armv5l-timesys-linux-uclibcgnueabi/toolchain/bin/armv5l-timesys-linux-uclibcgnueabi
export CXX=$TOOL_PREFIX-g++
export AR=$TOOL_PREFIX-ar
export RANLIB=$TOOL_PREFIX-ranlib
export CC=$TOOL_PREFIX-gcc
export LD=$TOOL_PREFIX-ld
export CCFLAGS=”-march=armv5te -mtune=arm926ej-s”
scons wordsize=32 snapshot=off arch=arm vfp3=off armeabi=soft sample=shell
Couple of issues I had.
Target is an Atmel (AT91SAM9G20) running Linux. Which means no hardware fpu, so the floating point emulation has to be software only.
Target libraries are uclibc, which has no support for backtrace. You get execinfo.h not found in platform-linux.cc.
Great.. thanks for the feedback!
Hi,
I’m trying to make it, but running into issues : even manually I got a -m32 error ? See logs … Any ideas ?
root@cross-ia32:~/cross/node-v0.6.11/deps/v8/host# scons -Y$V8DIR simulator=arm vfp3=off armeabi=soft snapshot=on
scons: Reading SConscript files …
scons: warning: Ignoring missing SConscript ‘obj/test/release/SConscript’
File “/root/cross/node-v0.6.11/deps/v8/SConstruct”, line 1475, in BuildSpecific
scons: done reading SConscript files.
scons: Building targets …
/root/arm-2009q1/bin/arm-none-linux-gnueabi-g++ -o obj/release/accessors.o -c -fno-rtti -fno-exceptions -fvisibility=hidden -Wall -W -Wno-unused-parameter -Wnon-virtual-dtor -Wno-abi -pedantic -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections -ansi -m32 -DUSE_EABI_HARDFLOAT=0 -DV8_TARGET_ARCH_ARM -DENABLE_DEBUGGER_SUPPORT -I/root/cross/node-v0.6.11/deps/v8/src /root/cross/node-v0.6.11/deps/v8/src/accessors.cc
cc1plus: error: unrecognized command line option “-m32″
scons: *** [obj/release/accessors.o] Error 1
scons: building terminated because of errors.
Hi Vincent,
Sorry to not see your comment earlier. It looks like your toolchain does not support the -m32 option. This was put in recently with the move to GYP build system in V8 (which this post did not cover). I think they did this to force ia32 builds when building the simulator. I can’t find the issue, but it was in the V8 bug tracker list.
Try overloading the CXXFLAGS… so take the above script, and just add an export CXXFLAGS in with your options. Your build is failing on g++.
http://code.google.com/p/v8/wiki/CrossCompilingForARM
http://code.google.com/p/v8/wiki/BuildingWithGYP
Excellent tutorial here, I’m in a situation here where I want a custom v8 shell in an armv5te environment, with a few extensions, but nothing as extensive as node.js.
However with the move to GYP I have been unable to find any clear instructions or documentation on using that to build v8 standalone instead of using scons. Any recommendations?