How to enable intrinsics in compiler? - android

Who can explain: how to enable intrinsics in c code?
I would like to use special dsp instructions in armv5TE
Consider qadd instruction, it nicely works when i use assembler approach, like this:
inline int function_qadd(int a, int b) {
__asm__ (
"qadd %0, %1, %2" : "=r" (a) : "r" (a), "r" (b));
return a;
}
But when i tried to use __qadd intrinsic instead of asm like this:
int add_result = __qadd(5,10);
LOGI("qadd='%d'", add_result);
i got error:
error: undefined reference to '__qadd'
What i am doing wrong, how to enable intrinsics in c code?
UPDATE:
I have ndk android-ndk-r8c (windows version), it have GCC 4.6 as default:
The GCC 4.6 compiler is still the default,
Besides i explicitly specify in android.mk
NDK_TOOLCHAIN_VERSION=4.6
My compiler flags is:
LOCAL_CFLAGS += -std=c99 -ffast-math -march=armv5te -mfpu=vfp -mfloat-abi=softfp
Besides i check the asm code generated by gcc throught -S compiler flag, it generate qadd instruction:
qadd r3, r3, r2

The intrinsic function __qadd is not available for the GCC compiler. The link to the documentation you've provided is for the (non-free) armcc compiler.
Using the assembler approach is the only practical way to use the qadd instruction if you're using GCC.

Related

Unable to run dynamically cross compiled application on arm device [duplicate]

I've two files:
lib.c
#include<stdio.h>
void hi() {
printf("Hi i'm a library function in lib.so\n");
}
and main.c
#include<stdio.h>
#include<dlfcn.h>
/* based on Jeff Scudder's code */
int main() {
void *SharedObjectFile;
void (*hi)();
// Load the shared libary;
SharedObjectFile = dlopen("./lib.so", RTLD_LAZY);
// Obtain the address of a function in the shared library.
ciao = dlsym(SharedObjectFile, "hi");
// Use the dynamically loaded function.
(*hi)();
dlclose(SharedObjectFile);
}
And I've tried to build an executables using the following commands:
export LD_LIBRARY_PATH=pwd
gcc -c -fpic lib.c
gcc -shared -lc -o lib.so lib.o
gcc main.c -ldl
And it works pretty well.
Then I've tried to export my program on Android (Nexus One, with ARM-v7-0a arch) using the following commands:
export LD_LIBRARY_PATH=pwd
arm-none-linux-gnueabi-gcc -c -fpic lib.c
arm-none-linux-gnueabi-gcc -shared -lc -o lib.so lib.o
arm-none-linux-gnueabi-gcc main.c -ldl -o main
adb push main /system/app
The result of executing ./main on the correct folder on my smartphone is just:
./main: not found
even if my file is right there!
Am I missing anything during the cross-compile process? Any help?
I'm using the cross-compiler from CodeSourcery and it works well for static programs without .so libraries.
Thanks
EDIT: as Igor states below, that was a linker issue. This command fixes it:
arm-none-linux-gnueabi-gcc -o test main.c -Wl,--dynamic-linker=/system/bin/linker -ldl
in my very case I need other libraries because in /system/lib/ there are no many .so files.
The "not found" message refers not to the shared object but to the dynamic linker. Linux uses /lib/ld-linux.so.2 (or /lib64/ld-linux-x86-64.so.2 for x64) while Android uses /bin/linker. You can check which dynamic loader your program uses with readelf -l, e.g.:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
You can specify a linker to use with ld's --dynamic-linker switch, but there are likely to be other differences. For example, Android uses a stripped-down libc implementation called bionic, and it may be missing functionality that your program relies on, or have different behavior.
You should use NDK or another Android-targeted toolchain when compiling programs for Android. Even though it's based on Linux kernel, the differences are large enough that Linux-targeted toolchains are not sufficient.

GCC to emit ARM idiv instructions (continued)

I am wondering if this is possible for a Krait 400 CPU. I followed some of the suggestions
here
When I compile with mcpu=cortexa15 , then the code compiles and effectively I see udiv instructions in the assembly dump.
However, I would like to know:
Is it possible to get it to work with march=armv7-a? (not specifying a cpu; this is how I have it originally)
I tried to use mcpu=krait2, but since I am not using the snapdragon llvm (I don't know yet how much effort that would be) it does not recognize it. Is it possible to get the cpu definition from the llvm and somehow make it available to my compiler?
Any other method/patch/trick?
My compiler options are as follows:
/development/android-ndk-r8e/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc -DANDROID -DNEON -fexceptions -Wno-psabi --sysroot=/development/android-ndk-r8e/platforms/android-14/arch-arm -fpic -funwind-tables -funswitch-loops -finline-limit=300 -fsigned-char -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=neon -fdata-sections -ffunction-sections -Wa,--noexecstack -marm -fomit-frame-pointer -fstrict-aliasing -O3 -DNDEBUG
The error that I get is:
Error: selected processor does not support ARM mode `udiv r1,r1,r3'
As a side note I have to say that I am just beginning o understand the whole scheme, therefore I want to keep it in small steps to understand what I am doing.
Thanks in advance.
EDIT 1:
I tried compiling a separate module only including the udiv instruction. That module is compiled using the -mcpu=cortex-a15 arameter, while the rest of the application is compiled using the -march=armv7-a parameter. The result was (somehow expected) that the function call overhead affected the time performance of the application. I could not get inline code since tring to get in inline resulted in the same error that I originally had. I will switch to the the Snapdragon to see if there is a better performance before trying to reinvent the wheel. Thanks everybody for their answers and tips.
idiv - an amalgam to mean both sdiv and udiv is supported is an optional Cortex-A instruction. The support by a Cortex-A can be queried via the ID_ISAR0 cp15 registers, in bits [27:24].
/* Get idiv support. */
unsigned int ISAR0;
int idiv;
__asm ("mrc 15, 0, %0, c0, c2, 0" :"=r" (ISAR0));
#ifdef __thumb2__
idiv = (ISAR0 & 0xf000000UL) ? 1 : 0;
#else
idiv = (ISAR0 & 0xf000000UL) == 0x2000000UL ? 1 : 0;
#endif
Bits [27:24] are 0001, if only thumb2 supports the udiv and sdiv instructions. If the bits [27:24] are 0010, then both modes support the instructions.
As the gcc flags -march=armv7-a, etc mean that the code should work on ALL CPUs of this type and this instruction is optional, it would be an error for gcc to emit this instruction.
You may compile different modules with different flags such as,
gcc -march=armv7-a -o general.o -c general.c
gcc -mcpu=cortex-a15 -D_USE_IDIV_=1 -o fast_idiv.o -c fast_div.c
These modules can be linked together and the above code can be used to select at run time an appropriate routine. For example, both files may have,
#include "fir_template.def"
and this file might have,
#ifdef _USE_IDIV_
#define _FUNC(x) idiv_ ## x
#else
#define _FUNC(x) x
#endif
int _FUNC(fir8)(FILTER8 *filter, SAMPLE *data,)
{
....
}
If you know your code will only run on a Cortex-a15, then use the -mcpu option. If you want this to run faster IF it can and be generic (support all armv7-a CPUs), then you must ID the CPU as outlined above and dynamically select the code.
Addendum: The files above (general.c and fast_idiv.c) could be put in separate shared libraries with the same API. Then interrogate /proc/cpuinfo and see if idiv is supported. Set the LD_LIBRARY_PATH (or dlopen()) to the appropriate version. The choice will depend on how much code is involved.

Error during Cross-compiling C code with Dynamic libraries

I've two files:
lib.c
#include<stdio.h>
void hi() {
printf("Hi i'm a library function in lib.so\n");
}
and main.c
#include<stdio.h>
#include<dlfcn.h>
/* based on Jeff Scudder's code */
int main() {
void *SharedObjectFile;
void (*hi)();
// Load the shared libary;
SharedObjectFile = dlopen("./lib.so", RTLD_LAZY);
// Obtain the address of a function in the shared library.
ciao = dlsym(SharedObjectFile, "hi");
// Use the dynamically loaded function.
(*hi)();
dlclose(SharedObjectFile);
}
And I've tried to build an executables using the following commands:
export LD_LIBRARY_PATH=pwd
gcc -c -fpic lib.c
gcc -shared -lc -o lib.so lib.o
gcc main.c -ldl
And it works pretty well.
Then I've tried to export my program on Android (Nexus One, with ARM-v7-0a arch) using the following commands:
export LD_LIBRARY_PATH=pwd
arm-none-linux-gnueabi-gcc -c -fpic lib.c
arm-none-linux-gnueabi-gcc -shared -lc -o lib.so lib.o
arm-none-linux-gnueabi-gcc main.c -ldl -o main
adb push main /system/app
The result of executing ./main on the correct folder on my smartphone is just:
./main: not found
even if my file is right there!
Am I missing anything during the cross-compile process? Any help?
I'm using the cross-compiler from CodeSourcery and it works well for static programs without .so libraries.
Thanks
EDIT: as Igor states below, that was a linker issue. This command fixes it:
arm-none-linux-gnueabi-gcc -o test main.c -Wl,--dynamic-linker=/system/bin/linker -ldl
in my very case I need other libraries because in /system/lib/ there are no many .so files.
The "not found" message refers not to the shared object but to the dynamic linker. Linux uses /lib/ld-linux.so.2 (or /lib64/ld-linux-x86-64.so.2 for x64) while Android uses /bin/linker. You can check which dynamic loader your program uses with readelf -l, e.g.:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
You can specify a linker to use with ld's --dynamic-linker switch, but there are likely to be other differences. For example, Android uses a stripped-down libc implementation called bionic, and it may be missing functionality that your program relies on, or have different behavior.
You should use NDK or another Android-targeted toolchain when compiling programs for Android. Even though it's based on Linux kernel, the differences are large enough that Linux-targeted toolchains are not sufficient.

how to execute qadd command in inline assembly in arm?

I got error when i tried to compile inline assembly with qadd command.
Error: cannot honor width suffix -- `qadd r7,r7,r1'
I know that qadd is supported in ARMv5TE
These ARM instructions are available in ARMv6 and above, and E
variants of ARMv5T.
C/asm code:
inline int __qadd(int a, int b) {
__asm__ (
"qadd %0, %1, %2" : "=r" (a) : "r" (a), "r" (b));
return a;
}
My cpu features is:
LOGI("__ARM_ARCH__='%d'", __ARM_ARCH__);
LOGI("__ARM_HAVE_5TE='%d'", __ARM_HAVE_5TE);
Output:
__ARM_ARCH__='5'
__ARM_HAVE_5TE='1'
I have next compiler flags:
LOCAL_CFLAGS += -std=c99 -ffast-math -march=armv5te
Besides i have tried replace add instead of qadd - nicely works but with qadd code not compiles.
What i'm doing wrong? Who can provide worked example of qadd command in assembly?
Solution here No qsort_r for Android (or how to disable force Thumb to use CLZ in Android ARM code)
In your Android.mk file, add ".arm" to the filenames and they will get
compiled as ARM mode instead of Thumb mode (e.g. sort.c.arm). I've had
mixed Thumb/ARM code in an Android native library and it worked fine.
Question is closed.

GCC 4.4.3 offsetof constant expression bug. How should I work around this?

I have a struct that contains a static constant expression that uses the offset macro defined in stddef.h
struct SomeType {
int m_member;
};
static const size_t memberOffset = offsetof(SomeType, m_member);
in GCC 4.4.3 (I'm using Androids NDK r7) this generates the following error:
arm-linux-androideabi-g++ -MMD -MP -MF ./obj/local/armeabi-v7a/... -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-exceptions -fno-rtti -O2 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300 - -I/Users/Byron/bin/android-ndk-r7/sources/cxx-stl/system/include -
-Wa,--noexecstack -O0 -g -w -D_ANDROID -I/blah/bin/android-ndk-r7/platforms/android-14/arch-arm/usr/include -c
/MyFile.h:330: error: '->' cannot appear in a constant-expression
/MyFile.h:330: error: '&' cannot appear in a constant-expression
This seems like a compiler bug. Does anyone have a good workaround for this? I found references to a bug of this nature on GCC 3.4 but not later versions. hmmm
Standards
In the C++98 standard, there's some information in
C.2.4.1 Macro offsetof(type, memberdesignator) [diff.offsetof]
The macro offsetof, defined in <cstddef>, accepts a restricted set of type arguments in this International
Standard. §18.1 describes the change.
(C.2.4.1 showed up with offsetof in the contents, so I went there first.) And:
§18.1 Types 18 Language support library
¶5 The macro offsetof accepts a restricted set of type arguments in this International Standard. type
shall be a POD structure or a POD union (clause 9). The result of applying the offsetof macro to a field that
is a static data member or a function member is undefined.
For comparison, the C99 standard says:
offsetof(type, member-designator)
which expands to an integer constant expression that has type size_t, the value of
which is the offset in bytes, to the structure member (designated by member-designator),
from the beginning of its structure (designated by type). The type and member designator
shall be such that given
static type t;
then the expression &(t.member-designator) evaluates to an address constant. (If the
specified member is a bit-field, the behavior is undefined.)
Your code
Your code meets the requirements of both the C++ and C standards, it seems to me.
When I use G++ 4.1.2 and GCC 4.5.1 on RedHat (RHEL 5), this code compiles without complaint with the -Wall -Wextra options:
#include <cstddef>
struct SomeType {
int m_member;
};
static const int memberOffset = offsetof(SomeType, m_member);
It also compiles without complaint with #include <stddef.h> and with the GCC compilers (if I use struct SomeType in the macro invocation).
I wonder - I got errors until I included <cstddef>...did you include that? I also added the type int to the declaration, of course.
Assuming that you haven't made any bloopers in your code, it seems to me that you probably have found a bug in the <cstddef> (or <stddef.h>) header on your platform. You should not be getting the error, and the Linux-based G++ appears to confirm that.
Workarounds?
You will need to review how offsetof() is defined in your system headers. You will then probably redefine it in such a way as not to run into the problem.
You might be able to use something like this, assuming you identify your broken system somehow and execute #define BROKEN_OFFSETOF_MACRO (or add -DBROKEN_OFFSETOF_MACRO to the command line).
#include <cstddef>
#ifdef BROKEN_OFFSETOF_MACRO
#undef offsetof
#define offsetof(type, member) ((size_t)((char *)&(*(type *)0).member - \
(char *)&(*(type *)0)))
#endif /* BROKEN_OFFSETOF_MACRO */
struct SomeType {
int m_member;
};
static const int memberOffset = offsetof(SomeType, m_member);
The size_t cast is present since the difference between two addresses is a ptrdiff_t and the offset() macro is defined to return size_t. The macro is nothing other than ugly, but that's why it is normally hidden in a system header where you don't have to look at it in all its ghastliness. But when all else fails, you must do whatever is necessary.
I know that once, circa 1990, I encountered a C compiler that would not allow 0 but it would allow 1024 instead. The distributed <stddef.h> header, of course, used 0, so I 'fixed' it by changing the 0 to 1024 (twice) for the duration (until I got a better compiler on a better machine).
offsetof() must be defined using pointer arithmetic.
GCC probably doesn't like that in constant expressions because in theory the pointers could change and so it is non-const.
Workaround might be make it a static int without const?

Categories

Resources