Skip to content

Commit f948f21

Browse files
Add arm softfloat variant as platform armel
- 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
1 parent 05567e4 commit f948f21

File tree

11 files changed

+438
-28
lines changed

11 files changed

+438
-28
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Features
99
--------
1010
* [#757](https://github.com/java-native-access/jna/issues/757): Build android archive (AAR) - [@matthiasblaesing](https://github.com/matthiasblaesing).
1111
* [#767](https://github.com/java-native-access/jna/pull/767): Add Win32 API mapping for Shlwapi PathIsUNC - [@ivanwick](https://github.com/ivanwick).
12+
* [#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).
1213

1314
Bug Fixes
1415
---------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
package com.sun.jna;
3+
4+
import java.io.File;
5+
import java.io.IOException;
6+
import org.apache.tools.ant.Project;
7+
8+
/**
9+
* Ant task to expose the arm soft-/hardfloat detection routines of the JNA core
10+
* for the build script.
11+
*
12+
* <p>The build script is expected to build a minimal set of classes that are
13+
* required to execute this. At the time of writing these are:</p>
14+
*
15+
* <ul>
16+
* <li>com.sun.jna.ELFAnalyser</li>
17+
* </ul>
18+
*/
19+
public class BuildArmSoftFloatDetector {
20+
21+
private String targetProperty;
22+
private Project project;
23+
24+
public void setProject(Project proj) {
25+
project = proj;
26+
}
27+
28+
/**
29+
* targetProperty receives the name of the property, that should take the
30+
* new property
31+
*
32+
* @param targetProperty
33+
*/
34+
public void setTargetProperty(String targetProperty) {
35+
this.targetProperty = targetProperty;
36+
}
37+
38+
public void execute() throws IOException {
39+
boolean result = false;
40+
// On linux /proc/self/exe is a symblink to the currently executing
41+
// binary (the JVM)
42+
File self = new File("/proc/self/exe");
43+
try {
44+
// The self.getCanonicalPath() resolves the symblink to the backing
45+
// realfile and passes that to the detection routines
46+
ELFAnalyser ahfd = ELFAnalyser.analyse(self.getCanonicalPath());
47+
result = ahfd.isArmSoftFloat();
48+
} catch (IOException ex) {
49+
result = false;
50+
}
51+
project.setNewProperty(targetProperty, Boolean.toString(result));
52+
}
53+
}

build.xml

+26-3
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,17 @@
208208
<property name="test.classes" location="${build}/test-classes"/>
209209
<property name="reports" value="${build}/reports"/>
210210

211+
<mkdir dir="${build}/ant-elfanalyser" />
212+
<javac classpath="lib/ant.jar" destdir="${build}/ant-elfanalyser" includeantruntime="false">
213+
<src path="src" />
214+
<src path="ant-elfanalyser-src" />
215+
<include name="**/ELFAnalyser.java" />
216+
<include name="**/BuildArmSoftFloatDetector.java" />
217+
</javac>
218+
219+
<taskdef name="BuildArmSoftFloatDetector" classname="com.sun.jna.BuildArmSoftFloatDetector" classpath="${build}/ant-elfanalyser" />
220+
<BuildArmSoftFloatDetector targetProperty="build.isArmSoftFloat"/>
221+
211222
<!-- Add other supported platforms here -->
212223
<condition property="jre.arch" value="x86">
213224
<matches pattern="(i[3456]86|pentium)" string="${os.arch}"/>
@@ -230,7 +241,15 @@
230241
<condition property="jre.arch" value="ppc64">
231242
<matches pattern="(powerpc64|power64)" string="${os.arch}"/>
232243
</condition>
244+
<condition property="jre.arch" value="armel">
245+
<and>
246+
<matches pattern="arm" string="${os.arch}"/>
247+
<matches pattern="true" string="${build.isArmSoftFloat}"/>
248+
</and>
249+
</condition>
250+
233251
<property name="jre.arch" value="${os.arch}"/>
252+
234253
<condition property="os.prefix" value="linux-${jre.arch}">
235254
<os name="Linux"/>
236255
</condition>
@@ -424,6 +443,8 @@ com/sun/jna/linux-x86-64/libjnidispatch.so;
424443
processor=x86-64;osname=linux,
425444
com/sun/jna/linux-arm/libjnidispatch.so;
426445
processor=arm;osname=linux,
446+
com/sun/jna/linux-armel/libjnidispatch.so;
447+
processor=armel;osname=linux,
427448
com/sun/jna/linux-aarch64/libjnidispatch.so;
428449
processor=aarch64;osname=linux,
429450
com/sun/jna/linux-ia64/libjnidispatch.so;
@@ -468,6 +489,9 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
468489
<zipfileset src="${lib.native}/linux-arm.jar"
469490
includes="*jnidispatch*"
470491
prefix="com/sun/jna/linux-arm"/>
492+
<zipfileset src="${lib.native}/linux-armel.jar"
493+
includes="*jnidispatch*"
494+
prefix="com/sun/jna/linux-armel"/>
471495
<zipfileset src="${lib.native}/linux-aarch64.jar"
472496
includes="*jnidispatch*"
473497
prefix="com/sun/jna/linux-aarch64"/>
@@ -666,6 +690,7 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
666690
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-x86.jar" overwrite="true"/>
667691
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-x86-64.jar" overwrite="true"/>
668692
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-arm.jar" overwrite="true"/>
693+
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-armel.jar" overwrite="true"/>
669694
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-aarch64.jar" overwrite="true"/>
670695
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-ia64.jar" overwrite="true"/>
671696
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/linux-ppc.jar" overwrite="true"/>
@@ -1318,6 +1343,4 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
13181343
<arg value="-Dgpg.useagent=true"/>
13191344
</artifact:mvn>
13201345
</target>
1321-
</project>
1322-
1323-
1346+
</project>

lib/ant.jar

1.94 MB
Binary file not shown.

lib/native/linux-armel.jar

46.1 KB
Binary file not shown.

nbproject/project.xml

+28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<type>org.netbeans.modules.ant.freeform</type>
44
<configuration>
55
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
6+
<name>JNA</name>
7+
</general-data>
8+
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/2">
69
<!-- Do not use Project Properties customizer when editing this file manually.
710
To prevent the customizer from showing, create nbproject/project.properties file and enter
811
auxiliary.show.customizer=false
@@ -12,15 +15,28 @@ auxiliary.show.customizer.message=<message>
1215
<name>JNA</name>
1316
<properties/>
1417
<folders>
18+
<source-folder>
19+
<label>JNA</label>
20+
<location>.</location>
21+
<encoding>UTF-8</encoding>
22+
</source-folder>
1523
<source-folder>
1624
<label>src</label>
1725
<type>java</type>
1826
<location>src</location>
27+
<encoding>UTF-8</encoding>
1928
</source-folder>
2029
<source-folder>
2130
<label>test</label>
2231
<type>java</type>
2332
<location>test</location>
33+
<encoding>UTF-8</encoding>
34+
</source-folder>
35+
<source-folder>
36+
<label>ant-elfanalyser-src</label>
37+
<type>java</type>
38+
<location>ant-elfanalyser-src</location>
39+
<encoding>UTF-8</encoding>
2440
</source-folder>
2541
</folders>
2642
<ide-actions>
@@ -51,6 +67,10 @@ auxiliary.show.customizer.message=<message>
5167
<label>test</label>
5268
<location>test</location>
5369
</source-folder>
70+
<source-folder style="packages">
71+
<label>ant-elfanalyser-src</label>
72+
<location>ant-elfanalyser-src</location>
73+
</source-folder>
5474
<source-file>
5575
<location>build.xml</location>
5676
</source-file>
@@ -63,15 +83,23 @@ auxiliary.show.customizer.message=<message>
6383
<ide-action name="test"/>
6484
</context-menu>
6585
</view>
86+
<subprojects/>
6687
</general-data>
6788
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
6889
<compilation-unit>
6990
<package-root>src</package-root>
91+
<classpath mode="compile">src</classpath>
7092
<source-level>1.5</source-level>
7193
</compilation-unit>
7294
<compilation-unit>
7395
<package-root>test</package-root>
7496
<unit-tests/>
97+
<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>
98+
<source-level>1.5</source-level>
99+
</compilation-unit>
100+
<compilation-unit>
101+
<package-root>ant-elfanalyser-src</package-root>
102+
<classpath mode="compile">src:lib/ant.jar</classpath>
75103
<source-level>1.5</source-level>
76104
</compilation-unit>
77105
</java-data>

src/com/sun/jna/ELFAnalyser.java

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
2+
package com.sun.jna;
3+
4+
import java.io.IOException;
5+
import java.io.RandomAccessFile;
6+
import java.nio.ByteBuffer;
7+
import java.nio.ByteOrder;
8+
import java.util.Arrays;
9+
10+
/**
11+
* Analyse an ELF file for platform specific attributes.
12+
*
13+
* <p>Primary use-case: Detect whether the java binary is arm hardfloat or softfloat.</p>
14+
*/
15+
class ELFAnalyser {
16+
/**
17+
* Generic ELF header
18+
*/
19+
private static final byte[] ELF_MAGIC = new byte[]{(byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F'};
20+
/**
21+
* e_flags mask if executable file conforms to hardware floating-point
22+
* procedure-call standard (arm ABI version 5)
23+
*/
24+
private static final int EF_ARM_ABI_FLOAT_HARD = 0x00000400;
25+
/**
26+
* e_flags mask if executable file conforms to software floating-point
27+
* procedure-call standard (arm ABI version 5)
28+
*/
29+
private static final int EF_ARM_ABI_FLOAT_SOFT = 0x00000200;
30+
private static final int EI_DATA_BIG_ENDIAN = 2;
31+
private static final int E_MACHINE_ARM = 0x28;
32+
private static final int EI_CLASS_64BIT = 2;
33+
34+
public static ELFAnalyser analyse(String filename) throws IOException {
35+
ELFAnalyser res = new ELFAnalyser(filename);
36+
res.runDetection();
37+
return res;
38+
}
39+
40+
private final String filename;
41+
private boolean ELF = false;
42+
private boolean _64Bit = false;
43+
private boolean bigEndian = false;
44+
private boolean armHardFloat = false;
45+
private boolean armSoftFloat = false;
46+
private boolean arm = false;
47+
48+
/**
49+
* @return true if the parsed file was detected to be an ELF file
50+
*/
51+
public boolean isELF() {
52+
return ELF;
53+
}
54+
55+
/**
56+
* @return true if the parsed file was detected to be for a 64bit architecture
57+
* and pointers are expected to be 8byte wide
58+
*/
59+
public boolean is64Bit() {
60+
return _64Bit;
61+
}
62+
63+
/**
64+
* @return true if the parsed file is detected to be big endian, false if
65+
* the file is little endian
66+
*/
67+
public boolean isBigEndian() {
68+
return bigEndian;
69+
}
70+
71+
/**
72+
* @return filename of the parsed file
73+
*/
74+
public String getFilename() {
75+
return filename;
76+
}
77+
78+
/**
79+
* @return true if file was detected to conform to the hardware floating-point
80+
* procedure-call standard
81+
*/
82+
public boolean isArmHardFloat() {
83+
return armHardFloat;
84+
}
85+
86+
/**
87+
* @return true if file was detected to conform to the software floating-point
88+
* procedure-call standard
89+
*/
90+
public boolean isArmSoftFloat() {
91+
return armSoftFloat;
92+
}
93+
94+
/**
95+
* @return true if the parsed file was detected to be build for the arm
96+
* architecture
97+
*/
98+
public boolean isArm() {
99+
return arm;
100+
}
101+
102+
private ELFAnalyser(String filename) {
103+
this.filename = filename;
104+
}
105+
106+
private void runDetection() throws IOException {
107+
// run precheck - only of if the file at least hold an ELF header parsing
108+
// runs further.
109+
RandomAccessFile raf = new RandomAccessFile(filename, "r");
110+
if (raf.length() > 4) {
111+
byte[] magic = new byte[4];
112+
raf.seek(0);
113+
raf.read(magic);
114+
if (Arrays.equals(magic, ELF_MAGIC)) {
115+
ELF = true;
116+
}
117+
}
118+
if (!ELF) {
119+
return;
120+
}
121+
raf.seek(4);
122+
// The total header size depends on the pointer size of the platform
123+
// so before the header is loaded the pointer size has to be determined
124+
byte sizeIndicator = raf.readByte();
125+
_64Bit = sizeIndicator == EI_CLASS_64BIT;
126+
raf.seek(0);
127+
ByteBuffer headerData = ByteBuffer.allocate(_64Bit ? 64 : 52);
128+
raf.getChannel().read(headerData, 0);
129+
bigEndian = headerData.get(5) == EI_DATA_BIG_ENDIAN;
130+
headerData.order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
131+
132+
arm = headerData.get(0x12) == E_MACHINE_ARM;
133+
134+
if(arm) {
135+
int flags = headerData.getInt(_64Bit ? 0x30 : 0x24);
136+
armSoftFloat = (flags & EF_ARM_ABI_FLOAT_SOFT) == EF_ARM_ABI_FLOAT_SOFT;
137+
armHardFloat = (flags & EF_ARM_ABI_FLOAT_HARD) == EF_ARM_ABI_FLOAT_HARD;
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)