The following line of code has been cross-compiled by using arm-linux-gnueabi-g++-4.7 on Ubuntu host machine. The prfm instruction was supposed to be generated for the particular line, but it was not.
__builtin_prefetch(&some_variable,0,3);
The command to compile is:
arm-linux-gnueabi-g++-4.7 -O0 -S -std=c++11 main.cpp -D some_definition
cat main.s | grep pr
//Returns null (main.s is all lower case)
Quoting one line from the gcc reference here related to the problem:
If the target does not support data prefetch, the address expression is evaluated if it includes side effects but no other code is generated and GCC does not issue a warning.
Last piece of information is that the cross compiler is installed by using apt-get install, not from scratch.
Here comes the question:
How can one simply add data prefetch support to the target of the arm-linux-gnueabi-g++-4.7 cross compiler?
Thanks in advance
As #Notlikethat suggested, compiling with -march=armv7-a solved the issue. Now there is a pld instruction in the assembly output.
$ arm-linux-gnueabi-g++-4.7 -g -O3 -std=c++11 -static -S -march=armv7-a main.cpp -D some_definition
$ cat main.s | grep pld
pld [r0, #0]
Related
I believe this question is significantly different from other, similar questions.
My flow is roughly this:
### Compile
%> gcc -ggdb3 file0.c ... -fno-builtin -c -o file0.o
%> gcc -ggdb3 file1.c ... -fno-builtin -c -o file1.o
...
%> gcc -ggdb3 fileN.c ... -fno-builtin -c -o fileN.o
### Link
%> gcc -ggdb3 -nostdlib -nodefaultlibs -Tscript.lds -Ttext=0x4000000 \
-Wl,--build-id=none -o main.elf file0.o file1.o ... fileN.o
### Disassemble
%> objdump -Stsxd main.elf > main.dis
I do not see the C code between lines of the disassembly file produced by objdump. See the image below for an example.
I don't blame objdump, because objdump --dwarf=decodedline main.elf shows nothing. I don't think the information is in the elf file.
I've fiddled with adding -g, -ggdb, and -gdwarf of various versions.
I've put full pathnames to files instead of relative paths.
I've tried -O0 to -O3.
The only flags not shown in my flow above are -W, -D, and -I flags.
If it matters, I'm using the Linaro port of gcc 6.4.1 targeting Cortex-A72 clusters. (My build machine is CentOS 7.9 on x86_64.) The commands to gcc and objdump above are prefixed to use that gcc version, and I see its banner from the debug section of the ELF in the disassembly file.
Is there some flag I am missing, or perhaps something I am adding (like -fno-builtin, or -Wl,--build-id=none) that could cause this?
Could my linker script file be stripping required information out, even though I provide a "debug" section (for .debug_info, .debug_line, and many other sections)?
Both objdump and readelf show a significant number of bytes in the debug section. What do I look for, more specifically?
edit:
I expect to see the kind of thing that is on the left of this image, but I see what is on the right:
I'm trying to compile VxWorks 7 SR660 on Wind River Workbench using clang version 10.0.1.1.
When compiling without debugging (-g flag) the compilation succeeds, when adding -g flag I get an error "error: unknown argument: '-g'".
The flags I use are:
clang -cc1 -triple=i386 -emit-obj -mrelocation-model static -fgnuc-version=4.2.1
-D __VXWORKS__ -D CPU=_VX_CORE -D TOOL_FAMILY=llvm -D TOOL=llvm -D _WRS_KERNEL -D _WRS_VX
_SMP -D _WRS_CONFIG_SMP -O0 -g -Wall -Wno-deprecated-declarations
Does anyone encounter this problem before?
Thank you.
Run clang -v, with and without the -g and compare the flags it uses for the -cc1 command. I find that without -g, it adds two flags: -debug-info-kind=limited and -dwarf-version=4. In other words, -g is a command for the compiler driver, not for the C compiler itself.
I cloned the Emacs source, with the intention of compiling to LLVM bytecode. I have been fiddling with Makefile flags for hours, but with no luck. Whenever I Google this, I get completely unrelated results about compiling .el files.
So I ask you this: how can I compile a project like Emacs to LLVM bytecode?
I am on OS X 10.9 Mavericks.
EDIT: I ran these commands:
CC=clang CFLAGS=-emit-llvm ./configure --with-jpeg=no --with-gif=no --with-tiff=no
then
CC=clang CFLAGS=-emit-llvm make
Then I got this error:
xml.c:23:10: fatal error: 'libxml/tree.h' file not found
#include <libxml/tree.h>
^
1 error generated.
When in fact libxml2 is already installed.
-emit-llvm only tells clang that you want any emitted assembly to be in LLVM IR. However, you still need to inform clang that you would like it to emit assembly to start with. This is done by using the -S flag. Additionally, to compile to LLVM bytecode, you need to use llvm-as. Lastly, you will have to do this for every single file, since AFAIK you cannot link LLVM bytecode files together, meaning that you will have many, many LLVM bytecode files.
Enough blabbering though, here's how you would do it for a given file (in the shell, not in the makefile, mind you):
$ clang -c foo.c -S -emit-llvm # additional options as necessary
$ llvm-as foo.s
$ ls
foo.bc foo.c foo.s
Explanation:
$ clang -c foo.c
Compile foo.c by itself without linking.
$ clang -c foo.c -S
Generate assembly and, if no output file is specified, save the results in foo.s.
$ clang -c foo.c -S -emit-llvm
Generate LLVM IR instead of native assembly.
$ llvm-as foo.s
Assemble foo.s and, if no output file is specified, save the results in foo.bc.
EDIT:
Apparently, this works too:
$ clang -c foo.c -emit-llvm -o foo.bc
The -o foo.bc above is because otherwise clang will output a .o file.
I want clang to compile my C/C++ code to LLVM bitcode rather than a binary executable. How can I achieve that?
And if I have the LLVM bitcode, how can I further compile it to a binary executable?
I want to add some of my own code to the LLVM bitcode before compiling to a binary executable.
Given some C/C++ file foo.c:
> clang -S -emit-llvm foo.c
Produces foo.ll which is an LLVM IR file.
The -emit-llvm option can also be passed to the compiler front-end directly, and not the driver by means of -cc1:
> clang -cc1 foo.c -emit-llvm
Produces foo.ll with the IR. -cc1 adds some cool options like -ast-print. Check out -cc1 --help for more details.
To compile LLVM IR further to assembly, use the llc tool:
> llc foo.ll
Produces foo.s with assembly (defaulting to the machine architecture you run it on). llc is one of the LLVM tools - here is its documentation.
Use
clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc
If you have multiple source files, you probably actually want to use link-time-optimization to output one bitcode file for the entire program. The other answers given will cause you to end up with a bitcode file for every source file.
Instead, you want to compile with link-time-optimization
clang -flto -c program1.c -o program1.o
clang -flto -c program2.c -o program2.o
and for the final linking step, add the argument -Wl,-plugin-opt=also-emit-llvm
clang -flto -Wl,-plugin-opt=also-emit-llvm program1.o program2.o -o program
This gives you both a compiled program and the bitcode corresponding to it (program.bc). You can then modify program.bc in any way you like, and recompile the modified program at any time by doing
clang program.bc -o program
although be aware that you need to include any necessary linker flags (for external libraries, etc) at this step again.
Note that you need to be using the gold linker for this to work. If you want to force clang to use a specific linker, create a symlink to that linker named "ld" in a special directory called "fakebin" somewhere on your computer, and add the option
-B/home/jeremy/fakebin
to any linking steps above.
If you have multiple files and you don't want to have to type each file, I would recommend that you follow these simple steps (I am using clang-3.8 but you can use any other version):
generate all .ll files
clang-3.8 -S -emit-llvm *.c
link them into a single one
llvm-link-3.8 -S -v -o single.ll *.ll
(Optional) Optimise your code (maybe some alias analysis)
opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
Generate assembly (generates a optimised.s file)
llc-3.8 optimised.ll
Create executable (named a.out)
clang-3.8 optimised.s
Did you read clang documentation ? You're probably looking for -emit-llvm.
I'm trying to compile a C program under Linux. However, out of curiosity, I'm trying to execute some steps by hand: I use:
the gcc frontend to produce assembler code
then run the GNU assembler to get an object file
and then link it with the C runtime to get a working executable.
Now I'm stuck with the linking part.
The program is a very basic "Hello world":
#include <stdio.h>
int main() {
printf("Hello\n");
return 0;
}
I use the following command to produce the assembly code:
gcc hello.c -S -masm=intel
I'm telling gcc to quit after compiling and dump the assembly code with Intel syntax.
Then I use th GNU assembler to produce the object file:
as -o hello.o hello.s
Then I try using ld to produce the final executable:
ld hello.o /usr/lib/libc.so /usr/lib/crt1.o -o hello
But I keep getting the following error message:
/usr/lib/crt1.o: In function `_start':
(.text+0xc): undefined reference to `__libc_csu_fini'
/usr/lib/crt1.o: In function `_start':
(.text+0x11): undefined reference to `__libc_csu_init'
The symbols __libc_csu_fini/init seem to be a part of glibc, but I can't find them anywhere! I tried linking against libc statically (against /usr/lib/libc.a) with the same result.
What could the problem be?
/usr/lib/libc.so is a linker script which tells the linker to pull in the shared library /lib/libc.so.6, and a non-shared portion, /usr/lib/libc_nonshared.a.
__libc_csu_init and __libc_csu_fini come from /usr/lib/libc_nonshared.a. They're not being found because references to symbols in non-shared libraries need to appear before the archive that defines them on the linker line. In your case, /usr/lib/crt1.o (which references them) appears after /usr/lib/libc.so (which pulls them in), so it doesn't work.
Fixing the order on the link line will get you a bit further, but then you'll probably get a new problem, where __libc_csu_init and __libc_csu_fini (which are now found) can't find _init and _fini. In order to call C library functions, you should also link /usr/lib/crti.o (after crt1.o but before the C library) and /usr/lib/crtn.o (after the C library), which contain initialisation and finalisation code.
Adding those should give you a successfully linked executable. It still won't work, because it uses the dynamically linked C library without specifying what the dynamic linker is. You'll need to tell the linker that as well, with something like -dynamic-linker /lib/ld-linux.so.2 (for 32-bit x86 at least; the name of the standard dynamic linker varies across platforms).
If you do all that (essentially as per Rob's answer), you'll get something that works in simple cases. But you may come across further problems with more complex code, as GCC provides some of its own library routines which may be needed if your code uses certain features. These will be buried somewhere deep inside the GCC installation directories...
You can see what gcc is doing by running it with either the -v option (which will show you the commands it invokes as it runs), or the -### option (which just prints the commands it would run, with all of the arguments quotes, but doesn't actually run anything). The output will be confusing unless you know that it usually invokes ld indirectly via one of its own components, collect2 (which is used to glue in C++ constructor calls at the right point).
I found another post which contained a clue: -dynamic-linker /lib/ld-linux.so.2.
Try this:
$ gcc hello.c -S -masm=intel
$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o hello.o -lc /usr/lib/crtn.o
$ ./hello
hello, world
$
Assuming that a normal invocation of gcc -o hello hello.c produces a working build, run this command:
gcc --verbose -o hello hello.c
and gcc will tell you how it's linking things. That should give you a good idea of everything that you might need to account for in your link step.
In Ubuntu 14.04 (GCC 4.8), the minimal linking command is:
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
/usr/lib/x86_64-linux-gnu/crt1.o \
/usr/lib/x86_64-linux-gnu/crti.o \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/ \
-lc -lgcc -lgcc_s \
hello.o \
/usr/lib/x86_64-linux-gnu/crtn.o
Although they may not be necessary, you should also link to -lgcc and -lgcc_s, since GCC may emit calls to functions present in those libraries for operations which your hardware does not implement natively, e.g. long long int operations on 32-bit. See also: Do I really need libgcc?
I had to add:
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/ \
because the default linker script does not include that directory, and that is where libgcc.a was located.
As mentioned by Michael Burr, you can find the paths with gcc -v. More precisely, you need:
gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'
This is how I fixed it on ubuntu 11.10:
apt-get remove libc-dev
Say yes to remove all the packages but copy the list to reinstall after.
apt-get install libc-dev
If you're running a 64-bit OS, your glibc(-devel) may be broken. By looking at this and this you can find these 3 possible solutions:
add lib64 to LD_LIBRARY_PATH
use lc_noshared
reinstall glibc-devel
Since you are doing the link process by hand, you are forgetting to link the C run time initializer, or whatever it is called.
To not get into the specifics of where and what you should link for you platform, after getting your intel asm file, use gcc to generate (compile and link) your executable.
simply doing gcc hello.c -o hello should work.
Take it:
$ echo 'main(){puts("ok");}' > hello.c
$ gcc -c hello.c -o hello.o
$ ld hello.o -o hello.exe /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtn.o \
-dynamic-linker /lib/ld-linux.so.2 -lc
$ ./hello.exe
ok
Path to /usr/lib/crt*.o will when glibc configured with --prefix=/usr