Skip to content

Commit

Permalink
Add arm softfloat variant as platform armel
Browse files Browse the repository at this point in the history
- add prebuild arm softfloat binaries
- add option to override prefix detection by specifying jna.prefix
- add prefix autodetection to platform code. Autodetection is
  based on the JVM image
- adjust build.xml to implement prefix detection

Closes: java-native-access#753
  • Loading branch information
matthiasblaesing committed Feb 24, 2017
1 parent 4f869f4 commit cf56797
Show file tree
Hide file tree
Showing 11 changed files with 517 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Features
--------
* [#757](https://github.com/java-native-access/jna/issues/757): Build android archive (AAR) - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#767](https://github.com/java-native-access/jna/pull/767): Add Win32 API mapping for Shlwapi PathIsUNC - [@ivanwick](https://github.com/ivanwick).
* [#753](https://github.com/java-native-access/jna/issues/753): Support arm hardfloat and softfloat by introducing armel as platform (ARM EABI Little-endian) - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#772](https://github.com/java-native-access/jna/pull/772): Improved speed of GDIUtil.getScreenshot() by ~30% - [@sommd](https://github.com/sommd).

Bug Fixes
Expand Down
53 changes: 53 additions & 0 deletions ant-elfanalyser-src/com/sun/jna/BuildArmSoftFloatDetector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

package com.sun.jna;

import java.io.File;
import java.io.IOException;
import org.apache.tools.ant.Project;

/**
* Ant task to expose the arm soft-/hardfloat detection routines of the JNA core
* for the build script.
*
* <p>The build script is expected to build a minimal set of classes that are
* required to execute this. At the time of writing these are:</p>
*
* <ul>
* <li>com.sun.jna.ELFAnalyser</li>
* </ul>
*/
public class BuildArmSoftFloatDetector {

private String targetProperty;
private Project project;

public void setProject(Project proj) {
project = proj;
}

/**
* targetProperty receives the name of the property, that should take the
* new property
*
* @param targetProperty
*/
public void setTargetProperty(String targetProperty) {
this.targetProperty = targetProperty;
}

public void execute() throws IOException {
boolean result = false;
// On linux /proc/self/exe is a symblink to the currently executing
// binary (the JVM)
File self = new File("/proc/self/exe");
try {
// The self.getCanonicalPath() resolves the symblink to the backing
// realfile and passes that to the detection routines
ELFAnalyser ahfd = ELFAnalyser.analyse(self.getCanonicalPath());
result = ahfd.isArmSoftFloat();
} catch (IOException ex) {
result = false;
}
project.setNewProperty(targetProperty, Boolean.toString(result));
}
}
29 changes: 26 additions & 3 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,17 @@
<property name="test.classes" location="${build}/test-classes"/>
<property name="reports" value="${build}/reports"/>

<mkdir dir="${build}/ant-elfanalyser" />
<javac classpath="lib/ant.jar" destdir="${build}/ant-elfanalyser" includeantruntime="false">
<src path="src" />
<src path="ant-elfanalyser-src" />
<include name="**/ELFAnalyser.java" />
<include name="**/BuildArmSoftFloatDetector.java" />
</javac>

<taskdef name="BuildArmSoftFloatDetector" classname="com.sun.jna.BuildArmSoftFloatDetector" classpath="${build}/ant-elfanalyser" />
<BuildArmSoftFloatDetector targetProperty="build.isArmSoftFloat"/>

<!-- Add other supported platforms here -->
<condition property="jre.arch" value="x86">
<matches pattern="(i[3456]86|pentium)" string="${os.arch}"/>
Expand All @@ -230,7 +241,15 @@
<condition property="jre.arch" value="ppc64">
<matches pattern="(powerpc64|power64)" string="${os.arch}"/>
</condition>
<condition property="jre.arch" value="armel">
<and>
<matches pattern="arm" string="${os.arch}"/>
<matches pattern="true" string="${build.isArmSoftFloat}"/>
</and>
</condition>

<property name="jre.arch" value="${os.arch}"/>

<condition property="os.prefix" value="linux-${jre.arch}">
<os name="Linux"/>
</condition>
Expand Down Expand Up @@ -424,6 +443,8 @@ com/sun/jna/linux-x86-64/libjnidispatch.so;
processor=x86-64;osname=linux,
com/sun/jna/linux-arm/libjnidispatch.so;
processor=arm;osname=linux,
com/sun/jna/linux-armel/libjnidispatch.so;
processor=armel;osname=linux,
com/sun/jna/linux-aarch64/libjnidispatch.so;
processor=aarch64;osname=linux,
com/sun/jna/linux-ia64/libjnidispatch.so;
Expand Down Expand Up @@ -468,6 +489,9 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
<zipfileset src="${lib.native}/linux-arm.jar"
includes="*jnidispatch*"
prefix="com/sun/jna/linux-arm"/>
<zipfileset src="${lib.native}/linux-armel.jar"
includes="*jnidispatch*"
prefix="com/sun/jna/linux-armel"/>
<zipfileset src="${lib.native}/linux-aarch64.jar"
includes="*jnidispatch*"
prefix="com/sun/jna/linux-aarch64"/>
Expand Down Expand Up @@ -666,6 +690,7 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-x86.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-x86-64.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-arm.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-armel.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-aarch64.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-ia64.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-ppc.jar" overwrite="true"/>
Expand Down Expand Up @@ -1318,6 +1343,4 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
<arg value="-Dgpg.useagent=true"/>
</artifact:mvn>
</target>
</project>


</project>
Binary file added lib/ant.jar
Binary file not shown.
Binary file added lib/native/linux-armel.jar
Binary file not shown.
107 changes: 107 additions & 0 deletions nbproject/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.ant.freeform</type>
<configuration>
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
<name>JNA</name>
</general-data>
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/2">
<!-- Do not use Project Properties customizer when editing this file manually.
To prevent the customizer from showing, create nbproject/project.properties file and enter
auxiliary.show.customizer=false
property there. Adding
auxiliary.show.customizer.message=<message>
will show your customized message when someone attempts to open the customizer. -->
<name>JNA</name>
<properties/>
<folders>
<source-folder>
<label>JNA</label>
<location>.</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
<label>src</label>
<type>java</type>
<location>src</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
<label>test</label>
<type>java</type>
<location>test</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
<label>ant-elfanalyser-src</label>
<type>java</type>
<location>ant-elfanalyser-src</location>
<encoding>UTF-8</encoding>
</source-folder>
</folders>
<ide-actions>
<action name="build">
<target>jar</target>
</action>
<action name="clean">
<target>clean</target>
</action>
<action name="javadoc">
<target>javadoc</target>
</action>
<action name="test">
<target>test</target>
</action>
<action name="rebuild">
<target>clean</target>
<target>jar</target>
</action>
</ide-actions>
<view>
<items>
<source-folder style="packages">
<label>src</label>
<location>src</location>
</source-folder>
<source-folder style="packages">
<label>test</label>
<location>test</location>
</source-folder>
<source-folder style="packages">
<label>ant-elfanalyser-src</label>
<location>ant-elfanalyser-src</location>
</source-folder>
<source-file>
<location>build.xml</location>
</source-file>
</items>
<context-menu>
<ide-action name="build"/>
<ide-action name="rebuild"/>
<ide-action name="clean"/>
<ide-action name="javadoc"/>
<ide-action name="test"/>
</context-menu>
</view>
<subprojects/>
</general-data>
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
<compilation-unit>
<package-root>src</package-root>
<classpath mode="compile">src</classpath>
<source-level>1.5</source-level>
</compilation-unit>
<compilation-unit>
<package-root>test</package-root>
<unit-tests/>
<classpath mode="compile">lib/hamcrest-core-1.3.jar:lib/junit.jar:lib/test/dom4j-1.6.1.jar:lib/test/guava-11.0.2.jar:lib/test/javassist-3.12.1.GA.jar:lib/test/reflections-0.9.8.jar:lib/test/slf4j-api-1.6.1.jar:src</classpath>
<source-level>1.5</source-level>
</compilation-unit>
<compilation-unit>
<package-root>ant-elfanalyser-src</package-root>
<classpath mode="compile">src:lib/ant.jar</classpath>
<source-level>1.5</source-level>
</compilation-unit>
</java-data>
</configuration>
</project>
140 changes: 140 additions & 0 deletions src/com/sun/jna/ELFAnalyser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@

package com.sun.jna;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

/**
* Analyse an ELF file for platform specific attributes.
*
* <p>Primary use-case: Detect whether the java binary is arm hardfloat or softfloat.</p>
*/
class ELFAnalyser {
/**
* Generic ELF header
*/
private static final byte[] ELF_MAGIC = new byte[]{(byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F'};
/**
* e_flags mask if executable file conforms to hardware floating-point
* procedure-call standard (arm ABI version 5)
*/
private static final int EF_ARM_ABI_FLOAT_HARD = 0x00000400;
/**
* e_flags mask if executable file conforms to software floating-point
* procedure-call standard (arm ABI version 5)
*/
private static final int EF_ARM_ABI_FLOAT_SOFT = 0x00000200;
private static final int EI_DATA_BIG_ENDIAN = 2;
private static final int E_MACHINE_ARM = 0x28;
private static final int EI_CLASS_64BIT = 2;

public static ELFAnalyser analyse(String filename) throws IOException {
ELFAnalyser res = new ELFAnalyser(filename);
res.runDetection();
return res;
}

private final String filename;
private boolean ELF = false;
private boolean _64Bit = false;
private boolean bigEndian = false;
private boolean armHardFloat = false;
private boolean armSoftFloat = false;
private boolean arm = false;

/**
* @return true if the parsed file was detected to be an ELF file
*/
public boolean isELF() {
return ELF;
}

/**
* @return true if the parsed file was detected to be for a 64bit architecture
* and pointers are expected to be 8byte wide
*/
public boolean is64Bit() {
return _64Bit;
}

/**
* @return true if the parsed file is detected to be big endian, false if
* the file is little endian
*/
public boolean isBigEndian() {
return bigEndian;
}

/**
* @return filename of the parsed file
*/
public String getFilename() {
return filename;
}

/**
* @return true if file was detected to conform to the hardware floating-point
* procedure-call standard
*/
public boolean isArmHardFloat() {
return armHardFloat;
}

/**
* @return true if file was detected to conform to the software floating-point
* procedure-call standard
*/
public boolean isArmSoftFloat() {
return armSoftFloat;
}

/**
* @return true if the parsed file was detected to be build for the arm
* architecture
*/
public boolean isArm() {
return arm;
}

private ELFAnalyser(String filename) {
this.filename = filename;
}

private void runDetection() throws IOException {
// run precheck - only of if the file at least hold an ELF header parsing
// runs further.
RandomAccessFile raf = new RandomAccessFile(filename, "r");
if (raf.length() > 4) {
byte[] magic = new byte[4];
raf.seek(0);
raf.read(magic);
if (Arrays.equals(magic, ELF_MAGIC)) {
ELF = true;
}
}
if (!ELF) {
return;
}
raf.seek(4);
// The total header size depends on the pointer size of the platform
// so before the header is loaded the pointer size has to be determined
byte sizeIndicator = raf.readByte();
_64Bit = sizeIndicator == EI_CLASS_64BIT;
raf.seek(0);
ByteBuffer headerData = ByteBuffer.allocate(_64Bit ? 64 : 52);
raf.getChannel().read(headerData, 0);
bigEndian = headerData.get(5) == EI_DATA_BIG_ENDIAN;
headerData.order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);

arm = headerData.get(0x12) == E_MACHINE_ARM;

if(arm) {
int flags = headerData.getInt(_64Bit ? 0x30 : 0x24);
armSoftFloat = (flags & EF_ARM_ABI_FLOAT_SOFT) == EF_ARM_ABI_FLOAT_SOFT;
armHardFloat = (flags & EF_ARM_ABI_FLOAT_HARD) == EF_ARM_ABI_FLOAT_HARD;
}
}
}
Loading

0 comments on commit cf56797

Please sign in to comment.