-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android Clang cross-compilation #39
Comments
You cannot build libgnat for several architectures at once, although here you may be missing a -fPIC switch instead when building the library? Since we don't know which change you made to the build and what platform/environment you are targetting, it's hard to comment further. |
I'm targeting Android (Bionic libc, at least aarch64, ideally arm as well). Changes were made to fix build with Android clang (just a few backports, also had to replace std::optional with llvm optional), I can upload them to GitHub later today. |
Object files are built using the following command (maybe with a different order, I'll make a minimal reproducible example later):
The resulting In fact, I even tried to build with |
`-fPIC` flag is present. So unless it's not working properly, it shouldn't be the issue.
OK, shouldn't be the issue then.
I'm targeting Android (Bionic libc, at least aarch64, ideally arm as well).
Do you have any suggestions on how to build it? I guess I can just build it twice for different architectures, but I don't see an easy way to build for anything except host.
You can pass switches used when building gnatlib via e.g:
make -C llvm-interface CFLAGS="-O2 --target=..." <your usual targets>
|
Object files are built using the following command (maybe with a different order, I'll make a minimal reproducible example later):
```
./llvm-gcc --target=aarch64-linux-android29 -fPIC -c -gnat2022 -O3 file.adb
```
The resulting `file.o` appears to have correct architecture (aarch64), but has those incompatible relocations.
OK, if you're already using the --target switch then this is something more subtle and
specific to aarch64-linux then or to the LLVM toolchain or binutils you are using.
In fact, I even tried to build with `--emit-llvm` and then used `llc -relocation-model=pic` with the same exact issue. Are the relocation type stored in LLVM IR?
This unfortunately goes beyond the general help around GNAT LLVM that we can provide,
you'll probably find more help in LLVM or Clang forums.
Arno
|
Will it build cross-compiler or the resulting llvm-gcc will be for aarch64? |
Can you upload your fork to github? I tried to compile gcc/gnat for Android last week and it failed because of headers, so having a build available would be useful for me. In your fork, can you specify the installed NDK's llvm? |
I'll upload all my changes later today. |
TBH, I'm not really bothered how it works as long as it does. |
It currently doesn't. That's why this issue exists. I found somewhat similar issue and |
No, CFLAGS only influences the runtime build and you are already specifying it. Building a cross compiler is done when configuring LLVM itself via the cmake flag -DLLVM_TARGETS_TO_BUILD= this is what determines the default/only target supported. There might be another LLVM_xxx cmake flag to specify the default BTW. |
Runtime is I'm using Android LLVM fork with a few patches from this repo applied (+ cherry-picks to fix build because it's 16.0.2), which is already the cross-compiler. |
Runtime is `libgnat_llvm.a`, right? AFAIR it is for x86 currently, so will something like `make gnartlib CFLAGS="-O2 --target=..."` will build it for the required target?
The runtime is called libgnat.a by default. I don't know where libgnat_llvm.a comes from, I suspect a customization on your end.
Your gnatlib build already includes the --target compiler switch, so I think your runtime
is already aarch64 and the issue is aarch64 specific, and the x86_64 is likely a red herring.
… I'm using Android LLVM fork with a few patches applied (+ cherry-picks, which is already the cross-compiler.
|
Nope, it's probably the compiler itself.
|
Uploaded changes to gnat-llvm, llvm_android, llvm-project I'm currently working on a minimal reproducible example of the issue. |
Uploaded to libmsg First issue I see is that llvm-gnatmake doesn't support
Apparently, I'm not supposed to run linker directly (thanks GCC for these great instructions), so let's try
This is definitely because of mixing aarch64 and x86-64, I've definitely seen similar errors before.
So |
Building
Apparently, gnat_src directory needs to be in include paths. Still doesn't compile:
clang just picked up OS include, which is why it doesn't work. However, this is still a GCC bug. aarch64's The final build command is:
|
And now we go back to those relocations. There was an ld.lld: error: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol '__gl_xdr_stream'; recompile with -fPIC
>>> defined in /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(init.o)
>>> referenced by s-stratt.adb
>>> s-stratt.o:(system__stream_attributes__i_ad) in archive /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a Interestingly, $ readelf -a init.o | grep __gl_xdr_stream
51: 0000000000000040 4 OBJECT GLOBAL DEFAULT 5 __gl_xdr_stream And $ readelf -a s-stratt.o -W | grep __gl_xdr_stream
0000000000000004 0000000c00000113 R_AARCH64_ADR_PREL_PG_HI21 0000000000000000 __gl_xdr_stream + 0
0000000000000008 0000000c0000011d R_AARCH64_LDST32_ABS_LO12_NC 0000000000000000 __gl_xdr_stream + 0 Found how it was compiled: /path/to/llvm-toolchain/gnat-llvm/llvm-interface/bin/llvm-gcc -c -x ada -gnatA -O2 --target=aarch64-linux-android29 -fPIC -Darm_pc=pc -I/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/../../../sysroots/ndk/arm64/usr/include -I/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/../../../sysroots/ndk/arm64/usr/include/aarch64-linux-android -I/path/to/llvm-toolchain/gnat-llvm/llvm-interface/gnat_src -Wno-implicit-function-declaration -I/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/include -nostdinc -I../adainclude -gnatg -gnatpg -gnatec=/tmp/GNAT-TEMP-000035.TMP -gnatem=/tmp/GNAT-TEMP-000048.TMP /path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude/s-stratt.adb Note that extern int __gl_xdr_stream;
int get_gl_xdr_stream(void) {
return __gl_xdr_stream;
} And it appears to produce different relocation types: $ readelf -a test.o -W | grep __gl_xdr_stream
0000000000000000 0000000700000137 R_AARCH64_ADR_GOT_PAGE 0000000000000000 __gl_xdr_stream + 0
0000000000000004 0000000700000138 R_AARCH64_LD64_GOT_LO12_NC 0000000000000000 __gl_xdr_stream + 0
7: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __gl_xdr_stream Same with Ada: with Interfaces.C; use Interfaces.C;
package Test_Ada is
XDR_Stream : int;
pragma Import (C, XDR_Stream, "__gl_xdr_stream");
function Get_XDR_Stream return int
with
Export => True,
Convention => C,
External_Name => "get_gl_xdr_stream_ada";
end;
with Interfaces.C; use Interfaces.C;
package body Test_Ada is
function Get_XDR_Stream return int is
begin
return XDR_Stream;
end;
end; And these wrong relocations are back again: $ readelf -a test_ada.o -W | grep __gl_xdr_stream
0000000000000000 0000000500000113 R_AARCH64_ADR_PREL_PG_HI21 0000000000000000 __gl_xdr_stream + 0
0000000000000004 000000050000011d R_AARCH64_LDST32_ABS_LO12_NC 0000000000000000 __gl_xdr_stream + 0
5: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __gl_xdr_stream This is either llvm or gnat-llvm bug, there's literally nothing except them used here. $ readelf -a test_ada_x64.o -W | grep __gl_xdr_stream
0000000000000002 0000000300000002 R_X86_64_PC32 0000000000000000 __gl_xdr_stream - 4
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __gl_xdr_stream Any suggestions on how to debug this further? |
LLVM IR dumps: ; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-android29"
@__gl_xdr_stream = external global i32, align 4
; Function Attrs: noinline nounwind optnone uwtable
define i32 @get_gl_xdr_stream() #0 {
%1 = load i32, ptr @__gl_xdr_stream, align 4
ret i32 %1
}
attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+crc32,+cx16,+cx8,+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{i32 7, !"frame-pointer", i32 2}
!4 = !{!"Android (dev, NO PGO PROFILE, NO BOLT PROFILE, based on r475365b) clang version 16.0.2 (https://android.googlesource.com/toolchain/llvm-project 080f09fc86284fa4fa7ca0824d87c10c9a763a4b)"} ; ModuleID = 'test_ada.adb'
source_filename = "test_ada.adb"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-android29"
@test_ada_E = dso_local global i16 0, align 2
@__gl_xdr_stream = external dso_local global i32, align 4
define i32 @get_gl_xdr_stream_ada() {
entry:
%0 = load i32, ptr @__gl_xdr_stream, align 4, !tbaa !2
ret i32 %0
}
!llvm.module.flags = !{!0, !1}
!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 0}
!2 = !{!3, !3, i64 0, i64 4}
!3 = !{!4, i64 4, !"interfaces__c__int#T1"}
!4 = !{!5, i64 4, !"interfaces__c__int#TN"}
!5 = !{!6, i64 4, !"interfaces__c__TintB#TN"}
!6 = !{!"Ada Root"}
Wow, how nice of |
$ ./main
Error: dlopen failed: cannot locate symbol "_r_debug" referenced by "/data/data/com.termux/files/home/libmsg/libmessage.so"... There are few other undefined symbols in library (after I added some system libraries to nm -D libmessage.so | grep -i ' u ' | grep -v LIBC
U __gnat_sigtramp
U _r_debug Any ideas where can I find them? |
I guess I can live without those. Exceptions will not work, but who cares. There are more serious issues.
And on Linux:
@ArnaudCharlet please reopen. While I found what was the cause of original issue with relocations (and it's certainly gnat-llvm bug), this is most likely another one. Edit: with hexValue of |
Minimal example would be: with Interfaces.C; use Interfaces.C;
function Test(hexValue: unsigned) return unsigned is
type Color is record
r: unsigned_char;
g: unsigned_char;
b: unsigned_char;
a: unsigned_char;
end record
with Convention => C_Pass_By_Copy;
function Get_Color(hexValue: unsigned) return Color
with
Import => True,
Convention => C,
External_Name => "GetColor";
function Color_To_Int(C: Color) return unsigned
with
Import => True,
Convention => C,
External_Name => "ColorToInt";
begin
return Color_To_Int(Get_Color(hexValue));
end;
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} Color;
extern Color GetColor(unsigned int hexValue);
extern unsigned ColorToInt(Color color);
unsigned c_test(unsigned hexValue) {
return ColorToInt(GetColor(hexValue));
} LLVM IR Dumps: ; ModuleID = 'test.adb'
source_filename = "test.adb"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-android29"
%test__color = type <{ i8, i8, i8, i8 }>
define i32 @_ada_test(i32 %hexvalue) local_unnamed_addr #0 {
entry:
%0 = tail call %test__color @GetColor(i32 %hexvalue)
%.fca.0.extract = extractvalue %test__color %0, 0
%.fca.1.extract = extractvalue %test__color %0, 1
%.fca.2.extract = extractvalue %test__color %0, 2
%.fca.3.extract = extractvalue %test__color %0, 3
%.sroa.4.0.insert.ext = zext i8 %.fca.3.extract to i32
%.sroa.4.0.insert.shift = shl nuw i32 %.sroa.4.0.insert.ext, 24
%.sroa.3.0.insert.ext = zext i8 %.fca.2.extract to i32
%.sroa.3.0.insert.shift = shl nuw nsw i32 %.sroa.3.0.insert.ext, 16
%.sroa.3.0.insert.insert = or i32 %.sroa.4.0.insert.shift, %.sroa.3.0.insert.shift
%.sroa.2.0.insert.ext = zext i8 %.fca.1.extract to i32
%.sroa.2.0.insert.shift = shl nuw nsw i32 %.sroa.2.0.insert.ext, 8
%.sroa.2.0.insert.insert = or i32 %.sroa.3.0.insert.insert, %.sroa.2.0.insert.shift
%.sroa.0.0.insert.ext = zext i8 %.fca.0.extract to i32
%.sroa.0.0.insert.insert = or i32 %.sroa.2.0.insert.insert, %.sroa.0.0.insert.ext
%1 = tail call i32 @ColorToInt(i32 %.sroa.0.0.insert.insert)
ret i32 %1
}
declare %test__color @GetColor(i32) local_unnamed_addr #0
declare i32 @ColorToInt(i32) local_unnamed_addr #0
attributes #0 = { "target-features"="+neon,+v8a," }
!llvm.module.flags = !{!0, !1}
!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 0} ; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-android29"
; Function Attrs: nounwind sspstrong uwtable
define i32 @c_test(i32 noundef %0) local_unnamed_addr #0 {
%2 = tail call i32 @GetColor(i32 noundef %0) #2
%3 = zext i32 %2 to i64
%4 = tail call i32 @ColorToInt(i64 %3) #2
ret i32 %4
}
declare i32 @ColorToInt(i64) local_unnamed_addr #1
declare i32 @GetColor(i32 noundef) local_unnamed_addr #1
attributes #0 = { nounwind sspstrong uwtable "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fix-cortex-a53-835769,+fp-armv8,+neon,+outline-atomics,+v8a" }
attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fix-cortex-a53-835769,+fp-armv8,+neon,+outline-atomics,+v8a" }
attributes #2 = { nounwind }
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{i32 7, !"frame-pointer", i32 1} Once again, this is not aarch64-specific. I'm getting the same errors on x86-64 (not even Android!). You may want to reproduce with |
I've reopened but I'm afraid this Issue is just too confused and with too many different issues mentioned to be actionable. The last one seems to be an issue with the C_Pass_By_Copy convention. |
Do you want me to split them?
typedef struct Image {
void *data;
int width;
int height;
int mipmaps;
int format;
} Image;
Image LoadImage(const char *fileName)
{
Image image = { 0 };
//...
return image;
} type Addr is mod 2 ** Standard'Address_Size;
type Image is record
Data: Addr;
Width: int;
Height: int;
Mipmaps: int;
Format: int;
end record
with Convention => C_Pass_By_Copy;
function Load_Image(File_Name: Char_Array) return Image
with
Import => True,
Convention => C,
External_Name => "LoadImage"; It actually doesn't segfault in the minimal example and only prints garbage on aarch64. This structure is too big to be passed by copy as it seems, but using just Image * __glue_LoadImage(Image *__return_storage_ptr__, char *fileName) {
Image image = LoadImage(fileName);
memcpy(__return_storage_ptr__, &image, sizeof(image));
return __return_storage_ptr__;
} It doesn't segfault anymore, but this is not a good solution. $ strings /system/bin/linker | grep -i _r_debug __dl__ZL16g__r_debug_mutex
__dl__r_debug
gnat-llvm/llvm-interface/lib/rts-native/adainclude/init.c:2782:30: error: no member named 'arm_pc' in 'struct sigcontext'
((mcontext_t *) mcontext)->arm_pc += 2; Fixed by |
Can you please open new issues for the gnat llvm specific items, so 1, 4 and 5 (and repost your proposed patches there). The rest is likely not in gnat llvm control. |
#42 is probably a good place to track the C structure passing issue. Please let me know if you don't agree and I should create a separate one, otherwise I'll add a few comments there with examples. Can you report 2, 3 and 7 to GCC? Since AdaCore is one of the main Ada GCC contributors, can you maybe even fix it? 6 is a gnat llvm issues though. Once you upgrade this repo for a newer LLVM (i.e. 18.0.1 for AOSP clang-r522817 or 19.0.0 for AOSP clang-r530567) it will partially be resolved, but |
I've been trying to build gnat-llvm with clang-r475365b and after some changes it builds just fine. However, compiling Ada programs doesn't work. Shared library build fails at the linking stage:
I believe this is due to libgnat_llvm.a built for x86-64. Is there a way to build it for several architectures at once?
The text was updated successfully, but these errors were encountered: