Open anonymix007 opened 3 months ago
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.
-fPIC
flag is present. So unless it's not working properly, it shouldn't be the issue.
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.
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):
./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.
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?
-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=..."
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 usedllc -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
make -C llvm-interface CFLAGS="-O2 --target=..."
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.
I actually haven't used NDK because it lacks necessary LLVM libraries and executables (i.e.opt
), one will need to build it from sources. Luckily, google has a build script (which I had to patch to retain those LLVM libraries and executables)
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 -Wl,-Bsymbolic
helped. I'll try it when I get back to my PC.
make -C llvm-interface CFLAGS="-O2 --target=..."
Will it build cross-compiler or the resulting llvm-gcc will be for aarch64?
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 libgnat_llvm.a
, right? AFAIR it is for x86 currently, so will something like make gnatlib CFLAGS="-O2 --target=..."
will build it for the required target?
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 likemake 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.
I don't know where libgnat_llvm.a comes from, I suspect a customization on your end.
Nope, it's probably the compiler itself.
$ readelf -h libgnat.a | grep Machine
Machine: Advanced Micro Devices X86-64
Uploaded changes to gnat-llvm, llvm_android, llvm-project
I'm currently working on a minimal reproducible example of the issue.
Uploaded to libmsg
It builds just fine for host (Linux, x86-64) with gcc-ada from system repos using build-linux-ada.sh
script once I rename libgnat_pic.a
to just libgnat.a
in /lib/gcc/x86_64-pc-linux-gnu/13.2.1/adalib
. This is either GCC or ArchLinux packaging bug, I guess.
First issue I see is that llvm-gnatmake doesn't support --target
option, but rather -target
, which in turn isn't actually supported by llvm-gnat1
. Using just llvm-gcc
allows to build message.o
, which is already good.
In order to make libmessage.so
I've tried to run ld.lld -shared message.o -o android/libmessage.so
, but it produced exactly those errors:
ld.lld: error: relocation R_AARCH64_ADD_ABS_LO12_NC cannot be used against symbol 'program_error'; recompile with -fPIC
>>> defined in message.o
>>> referenced by a-conhel.adb:0 (/path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adainclude/a-conhel.adb:0)
>>> message.o:(message__queue__implementation__te_check)
ld.lld: error: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol 'system__soft_links__abort_defer'; recompile with -fPIC
>>> defined in message.o
>>> referenced by a-convec.adb:65 (/path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adainclude/a-convec.adb:65)
>>> message.o:(message__queue__Oconcat__R908b___finalizer)
ld.lld: error: relocation R_AARCH64_LDST64_ABS_LO12_NC cannot be used against symbol 'system__soft_links__abort_defer'; recompile with -fPIC
>>> defined in message.o
>>> referenced by a-convec.adb:65 (/path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adainclude/a-convec.adb:65)
>>> message.o:(message__queue__Oconcat__R908b___finalizer)
ld.lld: error: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol 'system__soft_links__abort_undefer'; recompile with -fPIC
>>> defined in message.o
>>> referenced by a-convec.adb:0 (/path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adainclude/a-convec.adb:0)
>>> message.o:(message__queue__Oconcat__R908b___finalizer)
ld.lld: error: relocation R_AARCH64_LDST64_ABS_LO12_NC cannot be used against symbol 'system__soft_links__abort_undefer'; recompile with -fPIC
>>> defined in message.o
>>> referenced by a-convec.adb:65 (/path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adainclude/a-convec.adb:65)
>>> message.o:(message__queue__Oconcat__R908b___finalizer)
Apparently, I'm not supposed to run linker directly (thanks GCC for these great instructions), so let's try llvm-gnatlink
:
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: Relocations in generic ELF (EM: 183)
/usr/bin/ld: b~message.o: error adding symbols: file in wrong format
clang: error: linker command failed with exit code 1 (use -v to see invocation)
llvm-gnatlink: error when calling /path/to/llvm-toolchain/gnat-llvm/llvm-interface/bin/llvm-gcc
This is definitely because of mixing aarch64 and x86-64, I've definitely seen similar errors before.
Why it even calls host
UPD: There is ld
? Shouldn't it be using ld.lld
from AOSP clang?--LINK
option just for that. Seems to do something more interesting now:
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 'a-nbnbig.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vaispe.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-valspe.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vauspe.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vs_int.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vs_lli.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vs_llu.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vs_uns.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vsllli.o' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a: archive member 's-vslllu.o' is neither ET_REL nor LLVM bitcode
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-assert.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-btgbso.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-calari.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-calcon.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-caldel.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-calend.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-calfor.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-catizo.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cbdlli.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cbhama.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cbhase.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cbmutr.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cborma.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cborse.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cbprqu.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cbsyqu.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cdlili.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cgaaso.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cgarso.o) is incompatible with b~message.o
ld.lld: error: /path/to/llvm-toolchain/gnat-llvm/llvm-interface//lib/rts-native/adalib/libgnat.a(a-cgcaso.o) is incompatible with b~message.o
ld.lld: error: too many errors emitted, stopping now (use --error-limit=0 to see all errors)
llvm-gnatlink: error when calling /path/to/llvm-toolchain/out/install/linux-x86/clang-dev/bin/ld.lld
So libgnat.a
needs to be rebuilt for aarch64.
Building libgnat.a
using make gnatlib CFLAGS="-O2 --target=aarch64-linux-android29"
fails:
/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/bin/clang -c -x c -O2 --target=aarch64-linux-android29 -Wno-implicit-function-declaration -I/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/include -I../include -DIN_RTS=1 -fexceptions -DSTANDALONE -gdwarf-aranges -I/path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude /path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude/initialize.c
/path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude/init.c:2772:10: fatal error: 'sigtramp.h' file not found
#include "sigtramp.h"
^~~~~~~~~~~~
/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/bin/clang -c -x c -O2 --target=aarch64-linux-android29 -Wno-implicit-function-declaration -I/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/include -I../include -DIN_RTS=1 -fexceptions -DSTANDALONE -gdwarf-aranges -I/path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude /path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude/socket.c
1 error generated.
/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/bin/clang -c -x c -O2 --target=aarch64-linux-android29 -Wno-implicit-function-declaration -I/path/to/llvm-toolchain/out/install/linux-x86/clang-dev/include -I../include -DIN_RTS=1 -fexceptions -DSTANDALONE -gdwarf-aranges -I/path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude /path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude/mkdir.c
9 warnings generated.
compilation of init.c failed
gprbuild: *** compilation phase failed
make[2]: *** [Makefile:251: quicklib] Error 4
make[2]: Leaving directory '/path/to/llvm-toolchain/gnat-llvm/llvm-interface'
make[1]: *** [Makefile:215: gnatlib] Error 2
make[1]: Leaving directory '/path/to/llvm-toolchain/gnat-llvm/llvm-interface'
make: *** [Makefile:12: gnatlib] Error 2
Apparently, gnat_src directory needs to be in include paths. Still doesn't compile:
/path/to/llvm-toolchain/gnat-llvm/llvm-interface/lib/rts-native/adainclude/init.c:2782:30: error: no member named 'arm_pc' in 'mcontext_t'
((mcontext_t *) mcontext)->arm_pc += 2;
clang just picked up OS include, which is why it doesn't work.
However, this is still a GCC bug. aarch64's mcontext_t
does not have arm_pc
, it's just pc
.
The final build command is:
make gnatlib CFLAGS="-O2 --target=aarch64-linux-android29 -fPIC -Darm_pc=pc -I$CLANG_R475365B_CUSTOM/../../../sysroots/ndk/arm64/usr/include -I$CLANG_R475365B_CUSTOM/../../../sysroots/ndk/arm64/usr/include/aarch64-linux-android"
And now we go back to those relocations. There was an -fPIC
flag during the build of libgnat.a, but ld.lld
still fails with the exact same errors. There are many of them and they're repetitive (except symbol names), so showing just one:
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, __gl_xdr_stream
is defined in llvm-interface/gnat_src/init.c:
$ readelf -a init.o | grep __gl_xdr_stream
51: 0000000000000040 4 OBJECT GLOBAL DEFAULT 5 __gl_xdr_stream
And s-stratt.o
has references to it (limited to first 2 lines):
$ 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 -fPIC
flag is present.
Tried to build the following C program just for sanity check:
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:
test_ada.ads
:
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;
test_ada.adb
:
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. Actually, this is not even aarch64-specific:
$ 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"}
@__gl_xdr_stream = external dso_local global i32, align 4
Wow, how nice of llvm-gcc
to silently ignore -fPIC
.
$ ./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 libmessage.so
dependencies only these left):
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. Returning structures doesn't work. Source code is available here. Here's what it prints on Android (some strings omitted):
/data/data/com.termux/files/home/libmsg # ./main
GetColor: hexValue: 0x00000000, color: {0x00, 0x00, 0x00, 0x00}
ColorToInt: hexValue: 0x00680000, color: {0x00, 0x68, 0x00, 0x00}
c_uint_str: value: 0x00680000
GetColor: hexValue: 0x00680000, color: {0x00, 0x68, 0x00, 0x00}
0x00680000
(R => 0,
G => 104,
B => 0,
A => 0)
(R => 0,
G => 104,
B => 0,
A => 0)
And on Linux:
GetColor: hexValue: 0x00000000, color: {0x00, 0x00, 0x00, 0x00}
ColorToInt: hexValue: 0x00000000, color: {0x00, 0x00, 0x00, 0x00}
c_uint_str: value: 0x00000000
GetColor: hexValue: 0x00000000, color: {0x00, 0x00, 0x00, 0x00}
0x00000000
(R => 0,
G => 0,
B => 0,
A => 0)
(R => 0,
G => 0,
B => 0,
A => 0)
@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 0x12345678
it returns 0x12680000
. Something is clearly wrong here.
Minimal example would be:
test.adb
:
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;
test.c
:
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 build-linux-llvm-ada.sh
.
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? Currently I found these:
C_Pass_By_Copy
doesn't work properly at least for returning structures. Something fishy is also going on with passing them. LoadImage
segfaults literally on the first line:
typedef struct Image {
void *data;
int width;
int height;
int mipmaps;
int format;
} Image;
Image LoadImage(const char *fileName) { Image image = { 0 }; //... return image; }
```Ada
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 C
leads to the same results.
UPD As a workaround for passing issue I'm adding pragma Volatile_Full_Access(Addr);
. I have no idea what it does, but with it last 2 fields are consistently 0
(as they should be).
UPD2 And for returning issue using the following glue code works (unless C_Pass_By_Copy
is really needed, i.e. in those GetColor
examples):
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.
__gnat_sigtramp
is missing. Probably needs to be implemented for aarch64. Looks like GCC issue though._r_debug
is missing. It appears to be present in linker though:
$ strings /system/bin/linker | grep -i _r_debug __dl__ZL16g__r_debug_mutex
__dl__r_debug
-fPIC
is silently ignored. Fixed in 7f9614d96d2d3da8ee027acdf317c54172369b2b in my fork (please cherry-pick it from there)__gnat_sigtramp
. Attempted to fix in 75323602367d6741475457ca256deb228ed53714libstdc++.so
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 -Darm_pc=pc
in CFLAGS (though it might be broken completely, I have no idea what is this for).
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?