LLVM IR to Executable Segfaults after Compilation - compilation

I'm currently in the throes of writing a compiler for a toy language; this is a new area for me. I'm using the LLVM C++ API to generate LLVM IR and from there, an object.
The issue comes (I think) with linking the object and being able to execute it.
I have main.ll comprised of the utter minimum IR I could come up with:
define void #main() {
ret void
}
This runs just fine with lli main.ll, i.e. it does nothing.
I compile it to object format with: llc --filetype=obj -o main.{o,ll}.
And link to no existing library with: ld.lld -o main{,.o}
However the resulting binary immediately segfaults. I took the advice of a few tutorials which led me to try to link via GCC and I was informed that "[Relocations] can not be used when making a PIE object" which Wikipedia tells me refers to position independence in the resulting binary.
So I recompiled to object with: llc --filetype=obj --relocation-model=pic main.{o,ll} and recompiled with GCC and it worked, running the output did nothing as expected.
But running the ld.lld command again and attempting to run that binary, again, immediately segfaults.
So, the first question I had was: what step am I missing between linked-object (assuming I'm linking correctly) and binary for this simple example?
Is there an ld flag I'm missing, some required library even if I'm not making use of any one in particular?
There are then more issues even with the GCC method when I try to link against libc to make use of printf in the IR but I think I need a better understanding of this simple example before attacking that.
Any help would be appreciated.

For anyone else that finds this and is trying to make a .ll file into an executable: I've found that the C runtime libraries were what was missing. These are included by default by both gcc and clang but the -v options didn't give me much to go on sadly...
Using the relocation model under LLVM of PIC_ and linking the resulting object dynamically with the C runtime libs, I've managed to get the .ll file to run regularly.
An example command (obviously OS specific) would be:
ld --verbose -L/usr/lib -lc \
-dynamic-linker \
/lib64/ld-linux-x86-64.so.2 \
/usr/lib/Scrt1.o \
/usr/lib/crti.o \
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtbeginS.o \
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtendS.o \
<object file> \
-o <binary> \
/usr/lib/crtn.o
I'm not 100% sure on the "why" of the matter aside of guessing, but this works and your standard ld -L... -lc <object file> does not.
If anyone can provide clarification, I will happily accept their answer.

Related

undefined reference to libnuma

i'm trying to compile a simple test-program with libnuma (only numa_available is called) and i get a undefined reference error for this function.
At first, i used apt-get to install libnuma-dev and then simply used gcc -lnuma -o test test.c to compile the test program.
This led to 'undefined reference of numa_available'.
Then, I used dpkg -L libnuma-dev to make sure that the lib is actually installed (and just be sure I used strings to check whether the interface has changed or something - I know, this method is crap, but there were some "numa_available" strings in the lib, so i thought is rather safe to assume that the interface has not changed)
Then i also tried -l:/usr/lib/x86_64-linux-gnu/libnuma.so and -L/usr/lib/x86..gnu, however this always led to the undefined reference error.
Finally, i tried to statically link it (simply gcc -lnuma .... test.c /usr/lib../libnuma.a) and fortunately it works now...
However, can anyone tell me why it does not work dynamically linked?
best regards
Judging from your link command ("gcc -lnuma .... test.c /usr/lib../libnuma.a"), the most likely reason is that you need to move -lnuma to after test.c. --as-needed flag is enabled by default in modern distros and will not link in library unless it has been referred by preceeding objects.

How to compile fortran code to run without gfortran installed

I have downloaded Bellhop, which is an underwater acoustic simulator written in Fortran. It can be found here with the Makefile.
Question 1: I would like to know if it is possible to compile Fortran code, including everything needed, so a user without gfortran installed, can run it.
I have read here the following:
static linking
This section does not apply to Windows users, except for Cygwin users with gcc4-4.3.2-2 or later.
gfortran is composed of two main parts: the compiler, which creates the executable program from your code, and the library, which is used when you run your program afterwards. That explains why, if gfortran is installed in a non-standard directory, it may compile your code fine but the executable may fail with an error message like library not found. One way to avoid this (more ideas can be found on the binaries page) is to use the so-called "static linking", available with option -static gfortran then put the library code inside the program created, thus enabling it to run without the library present (like, on a computer where gfortran is not installed). Complete example is:
gfortran -static myfile.f -o program.exe
Reading this, I suppose that it is possible to do what I'm asking but I'm not very familiarized with fortran and makefiles. I don't understand this:
put the library code inside the program created
Question 2: How can I put the library code inside the program? Where can I find the library? What does "inside the program" means?
I'm running OSX 10.9.4 and gfortran
I solved my problem about compiling Fortran code with gfortran using static libraries.
As #M.S.B. said, using static-libgfortran worked for me under MacOS.
If somebody is having issues with linking the libquadmath.0.dylb library, remove libquadmath.0.dylib and libquadmath.dylib from /usr/local/gfortran/lib/
This doest the trick. Further information can be found here
I think the meaning of the bold part is actually
gfortran then puts the library code inside the
program created
That means using -static should be enough, there is no additional step. Just be advised you will need a static version of all the libraries that you link with.
I know this is very old tracker, but maybe somebody will be still interested in the solution that works.
Let's say we have code:
! fort_sample.f90
program main
write (*,*) 'Hello'
stop
end
First, compile the stuff:
gfortran -c -o fort_sample.o fort_sample.f90
Then, link stuff
ld -o ./fort_sample -no_compact_unwind \
-arch x86_64 -macosx_version_min 10.12.0 \
-lSystem \
/usr/local/gfortran/lib/libgfortran.a \
/usr/local/gfortran/lib/libquadmath.a \
/usr/local/gfortran/lib/gcc/x86_64-apple-darwin16/6.3.0/libgcc.a \
fort_sample.o
You can execute it
./fort_sample
Hello
You can notice that quadmath is no longer there
> otool -L fort_sample
fort_sample:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.51.1)
I guess this is what you were looking for in a first place. No removing dylibs, no symbolic links, etc.
The current version of the option is -static-libgfortran. This means that the Fortran specific libraries of gfortran will be included into the executable. These are libraries are automatically found for a good installation of gfortran. This should produce an executable that should run on other computers with the same OS, even if that computer doesn't have gfortran installed. This option likely doesn't statically link all libraries, so there is some risk that some other shared library used on your computer won't be available on the other computer.

C compiler for mac?

I'm working through a text on linking, and wanted to work along with some examples in said text.
To better understand whats going on when I invoke the gcc driver, I was looking into doing all the compilation old-school by hand;
preprocessing using cpp
compiling with cc1
assembling with as
linking using ld
Unfortunately, on my Mac I don't seem to be able to reference cc1directly (no listing of cc1 in man). What are my options?
Read some material about GCC internals. First the wikipage on GCC. Then, you could play with the MELT probe (you may want a Linux system to use it).
Then read the GCC manual. And the GCC resource center
Use gcc -v -Wall to compile, it will show what cc1 is running (and -Wall is always useful). So try compiling with gcc -v -Wall hello.c -o helloworld.bin
the cc1 program don't sit in your PATH or in /usr/bin/ but -on my system- in /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1
The command gcc -print-prog-name=cc1 will tell you which cc1 is used by your gcc. See GCC debugging options for more.
The preprocessing is now inside cc1.
The gcc program is just a driver, starting cc1 (which does most of the compiling work), then as, ld etc...
The MELT site contains some documentation, and some slides explaining GCC, which you could find interesting. MELT is a domain specific language to extend GCC.
See also the picture on http://starynkevitch.net/Basile/gcc-melt/cc1-internals.svg and the below picture
picture from http://starynkevitch.net/Basile/gcc-melt/gcc-MELT-inside.png, done by me, CC BY SA
The cc1 is producing a .s assembly file; the as (started by gcc) is transforming it into .o. The ld linker (started by gcc) will produce a library or an executable.
PS. I have a Linux system, but things are very similar on MacOSX.
reference on linking
A good book about linking is Levine's Linkers & loaders book.
PS. MELT is obsolete in 2021, but I am working on the Bismon static source code analyzer and on RefPerSys (which generates C++ code).
For reference, I installed gcc-10 with brew on my macOS (Catalina).
While cc1 is not directly accessible (via PATH), it can be found in
/usr/local/Cellar/gcc/10.2.0/libexec/gcc/x86_64-apple-darwin19/10.2.0
If you are lost, try gcc -v and from the verbose information you may find where your cc1 is.

How to set up Xcode to run OpenCL code, and how to verify the kernels before building

I am looking at the official documentation on the Apple site, and I see that there is a quickstart about how to use OpenCL on Xcode.
Maybe it is just me, but I had no luck building the code that is mentioned on the "hello world OCL" section.
I've started Xcode and created an empty project; created a main.c and a .cl kernel file, pasting what is on the Apple developer site, and I am not able to get anything to build, even after adding a target.
The AD site does not have a project to download, so I have no clue about the cause of the failure (it may be me most likely, or the site assume steps and does not mention them).
I've also tried the sample project from macresearch.org, but they are quite ancient, and the test project in the 3rd lesson is not running at all.
Now, I am pretty sure that others are using Xcode to run OCL code, but I cannot find any single page (except the aforementioned macresearch.org) that gives a clear setup about how to run an Xcode project with OCL. Is there anyone aware of a tutorial that shows how to work with OCL and Xcode?
I have purchased 3 books on OCL (Gaster's Heterogeneous computing with OpenCL, Scarpino's OpenCL in action and Munshi's OpenCL programming guide), and neither mention how to set up Xcode, while they go in detail for the visual studio setup and even for the eclipse setup.
On the side; is there any application that is able to validate kernel code before running it in the OCL application?
Thanks in advance for any suggestion that you may have.
Short answer: https://developer.apple.com/library/mac/#documentation/Performance/Conceptual/OpenCL_MacProgGuide/XCodeHelloWorld/XCodeHelloWorld.html
Long answer for command liners:
With a recent Xcode (and Lion or higher), you don't even need to call clCreateProgramWithSource, just write your kernel and call it from your app, there are some additional compiling steps needed though.
I'm taking the OpenCL Hello World example from Apple here using default compiler flags (see https://developer.apple.com/library/mac/#documentation/Performance/Conceptual/OpenCL_MacProgGuide/ExampleHelloWorld/Example_HelloWorld.html) and showing the steps Xcode would do in the background.
To get you started, do a:
/System/Library/Frameworks/OpenCL.framework/Libraries/openclc -x cl -cl-std=CL1.1 -cl-auto-vectorize-enable -emit-gcl mykernel.cl
This will create 2 files, mykernel.cl.h and mykernel.cl.c (and mykernel.cl.c does all the magic of loading your kernel into the app). Next you'll need to compile the kernel:
/System/Library/Frameworks/OpenCL.framework/Libraries/openclc -x cl -cl-std=CL1.1 -Os -triple i386-applecl-darwin -emit-llvm-bc -o mykernel.cl.i386.bc mykernel.cl
/System/Library/Frameworks/OpenCL.framework/Libraries/openclc -x cl -cl-std=CL1.1 -Os -triple x86_64-applecl-darwin -emit-llvm-bc -o mykernel.cl.x86_64.bc mykernel.cl
/System/Library/Frameworks/OpenCL.framework/Libraries/openclc -x cl -cl-std=CL1.1 -Os -triple gpu_32-applecl-darwin -emit-llvm-bc -o mykernel.cl.gpu_32.bc mykernel.cl
And last but not least, build the app itself:
clang -c -Os -Wall -arch x86_64 -o mykernel.cl.o mykernel.cl.c
clang -c -Os -Wall -arch x86_64 -o square.o square.c
clang -framework OpenCL -o square mykernel.cl.o square.o
And that's it. You won't see any clCreateProgramWithBinary or clCreateProgramWithSource in Apple's sample code. Everything is done via mykernel.cl.c generated by openclc.
So seems that I was able to partially resolve the issue in this way:
Create an empty project, create a main.c file and a kernel file
create a target as console application
in the build settings, add the OpenCL framework (you will see it appearing on the file browser in the left pane, if it will be added correctly).
specify the location where the kernel file is located, hardcoding the path (it is not enough to just say "my kernel.cl"; Xcode for some reasons don't get that the cl file is in the same dir as the main, so you gotta specify the path when loading the kernel file)
I was successful using these steps, while using the example code on the Apple developer site.
I am pretty sure that there are other ways to do this, but at least this may help whom, like me, had no clue about how to start.
To answer the second part of your question, on Mountain Lion you can run the OpenCL compiler on foo.cl like this:
/System/Library/Frameworks/OpenCL.framework/Libraries/openclc \
-c -Wall -emit-llvm -arch gpu_32 -o foo.bc foo.cl
It will compile foo.cl to LLVM bit-code foo.bc. This binary file can be used with clCreateProgramWithBinary, which is faster than clCreateProgramWithSource. Valid values for -arch are i386 x86_64 gpu_32.

GCC - Linking is unsuccessful

and sorry for my not really good english. I'll try my best :)
I am trying to compile a addin for my Casio graphic calculator in C. This works without problems when using the official SDK. Because it is only available for Windows, I want to use gcc.
So I got sh-rtems-gcc and it's binutils from macports and tried to compile my program according to this instructions. I copy-pasted the described addin.ld and crt0.s and placed my main.c and libfxsys.a (from the same guys as the instructions mentioned above) in the same directory. The sub-dir include contains fxsys' headers. I verified the presence of all the functions of the library in the .a file with nm.
When using this command for compilation:
sh-rtems-gcc-4.2.3 -m3 -mb -nostdlib -I./include -c crt0.s main.c
Everything works fine. But then im trying to link:
sh-rtems-gcc-4.2.3 -m3 -mb -nostdlib -L. -o myaddin.elf -Taddin.ld crt0.o main.o -lfxsys
and get the following error:
main.o: In function `__main':
main.c:(.text+0x248): undefined reference to `_Bdisp_AllClr_VRAM'
...
... (--- cut 16 other errors in the same format ---)
...
main.c:(.text+0x360): undefined reference to `_Sleep'
./libfxsys.a(locate.o): In function `_locate':
locate.c:(.text+0x28): undefined reference to `_locate_OS'
collect2: ld gab 1 als Ende-Status zurück
All the missing symbols are in the libfxsys.a. I have verified this with nm.
I have already played with the positions of the library in the command, as this is often mentioned as a source of failure in other posts found in google, but without success. I also tried adding and removing the -lgcc option that is used in the above mentioned instructions, without success.
My Host-Machine is a Intel Mac, OS X 10.6
Because I have no idea how to solve this problem, and get to compile my program, I have to ask: What am I doing wrong? How can I compile my program without using the SDK?
Thanks in advance,
xythobuz
Edit:
I have also tried linking with:
sh-rtems-ld -EB -L. -o myaddin.elf -Taddin.ld crt0.o --start-group main.o libfxsys.a --end-group
But it produces the same output as above.
I can't say the exact problem, but would investigate like this:
Find the library that contains the missing symbols. Use nm to see symbol names
Once you know which library contains the symbols make sure you're linking to it, and in the correct order. Try using recursive symbol resolution options -( -) with your linker.

Resources