Cross compilation: GCC ignores --sysroot - gcc

I'm trying to cross compile programs (currently avconv from libav) for a Nokia N9 phone using arm-linux-gnueabi-gcc from Linux Mint's 64-bit repository. The compiler's libc version is 2.15 and the phone has libc-2.10.1. They have an incompatibility in the math library, which gives me a segfault when I compile and run the avconv program from libav.
I'd need to compile and link against the older libc version, but I haven't managed to get the --sysroot option to work.
I made a small test program to avoid repeatedly configuring and compiling libav.
arm-linux-gnueabi-gcc --sysroot=/opt/CrossCompilation/NokiaN9/ -o output.sysroot hello.c
arm-linux-gnueabi-gcc -o output.nosysroot hello.c
Both commands create an identical output file. This is what hello.c looks like:
#include <stdio.h>
#include <math.h>
int main() {
printf("Hello, World! Sin = %f\n", sin(0.6451));
}
The strangest part is that gcc completely ignores the --sysroot option. If I pass a nonexisting directory to sysroot, it still produces exactly the same output binary:
arm-linux-gnueabi-gcc --sysroot=/foo/bar -o output.foobar hello.c
It doesn't even complain about any errors. What's the problem?

since I wasted a few days messing with this before reading the comments, I'm going to post artless noise's comments as an answer:
"Run the compiler with arm-linux-gnueabi-gcc -v and look at the value of --with-sysroot; this is the directory the compiler was built with. If you have this directory present on your machine (maybe with a different compiler), then the --sysroot may not work[; and if you do not see --with-sysroot and instead see --with-libs, it] means your gcc is compiled without --sysroot support."

Related

Lift x64 Windows executable to LLVM bitcode and then compile back to x32 one?

So my idea is to "lift" 64-bits Windows executable to LLVM bitcode (or whatever is higher than assembly) and then compile it back to 32-bit executable.
I found that RetDec and McSema can lift PE binary to LLVM IR (and optionally C), but McSema requires IDA pro so I haven't tried it yet.
I have installed MSVC v143 and Windows SDK version 10.0.19041.0:
Clang version:
clang version 13.0.1 (https://github.com/llvm/llvm-project 75e33f71c2dae584b13a7d1186ae0a038ba98838)
Target: x86_64-pc-windows-msvc
Thread model: posix
So I compile this Hello World code in C using Clang:
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
}
then clang hello.c -o hello.exe
Check hello.exe file type with WSL:
$ file hello.exe
hello.exe: PE32+ executable (console) x86-64, for MS Windows
You can download it here.
Then I use RetDec to lift it to LLVM IR:
python retdec-decompiler.py --no-memory-limit hello.exe
Output: here
After that we get:
Compile bitcode back to executable:
clang hello.exe.bc -m32 -v -Wl,/SUBSYSTEM:CONSOLE -Wl,/errorlimit:0 -fuse-ld=lld -o hello.x86.exe
Output: here
I guess functions like _WriteConsoleW are Win32 APIs, but ___decompiler_undefined_function_0 might be generated from the decompiler by some way.
Also, the decompiled code has no main function, but it had entry_point function. From hello.exe.ll:
hello.exe.c also has entry_point instead of main:
And also, hello.exe.c doesn't have ___decompiler_undefined_function_0
I also tried running the bitcode with lli:
lli --entry-function=entry_point hello.exe.bc
Output: here
Here is the link to the files.
How to make this compile? Thanks!
That's very ambitious.
I'm going to go out on a limb and say that every windows application includes thousands of system header files, most of which use types whose size differs between 32- and 64-bit systems and many of which contains #ifdef or other platform-dependent differences. You'll have a large .ll file full of windows64-specific types and code.
If the developers at Microsoft saw windows64 as a good chance to drop some hacks that were needed for w95 code, then you'll have w32-incompatible code there, too.
What you have to do is what the wine developers did — add code to cater to each problem in turn. There will be thousands of cases to handle. Some of it will be very difficult. When you see the number 128 in the .ll file, was it sizeof(this_w64_struct) in the original source, sizeof(that_other_struct) or something else entirely? Should you change the number, and if so, to what?
You should expect this project to take at least years, maybe a decade or more. Good luck.

Compiling C code with gcc without a makefile on Mac M1

I am new to MacOS, I've always written code on Linux. I was used to compiling C files with gcc, simply like
gcc -o file file.c -lm -lgsl
where here I assumed the code to contain among its includes
#include <math.h>
#include <gsl/gsl_rng.h>
Of course the library gsl is correctly installed on my Mac via homebrew, and so are pkg-config and "Command line tools", but still when I try to compile file.c I get an error message,
fatal error: 'gsl/gsl_rng.h' file not found
#include <gsl/gsl_rng.h>
^~~~~~~~~~~~~~~
The problem is not specific to gsl (I tried for instance with the library fftw3 and got the same result).
I've seen tons of people with the same kind of problems on new M1 Macs; I've read that gcc on Mac is really "clang", and different rules apply. A ton of mocking answers were suggesting to add the correct library paths to the makefile or the like. But actually I've never before felt the need for a makefile on Linux, and surely I don't want to start adding cflags and paths whenever I compile a code (I'm working on several machines with different operating systems, with my code stored on Cloud servers, so I assume I should write a makefile for each of them? Really?).
Has anyone found a proper fix?

Link against shared library with SONAME

How can I force the gcc linker to link against a given version (soname) of a shared library on the system?
I need this to enforce that the version of openssl that is #include'ed matches the version that is linked, on any system, even if multiple versions of openssl are installed. To find the ABI version, my configure script first compiles and runs a program that extracts the SONAME from the headers:
#include <openssl/opensslv.h>
#include <stdio.h>
int main () {
printf(SHLIB_VERSION_NUMBER);
return 0;
}
The SHLIB_VERSION_NUMBER contains the so version string, e.g. 0.9.8 or 1.0.2k or 1.1.0. But how do I tell gcc to link against this version of libssl or libcrypto rather than just any -lssl?
I tried "in situ" linking, so that instead of linking with gcc main.c -lcrypto we use:
gcc main.c libcrypto.so.1.1.0
However it seems the linker libcrypto.so.1.1.0 cannot be found:
gcc: error: libcrypto.so.1.1.0: No such file or directory
I guess the system only searches in the standard locations when using the -l flag. Is there a better way to make my software link against libcrypto.so.1.1.0?
To select the correct version of the openssl shared libraries use:
gcc main.c -l:libssl.so.1.0.0 -l:libcrypto.so.1.0.0
The key to answering this question is "how do I control ld so that is links the correct version of a shared library?".
The correct way to pass a linker flag (a command line parameter to ld) using the gnu compilers (gcc, g++, gdc, etc...) is to use the normal ld parameter prefixed with "-l". For example -lssl or -L/usr/local/lib.
Edit: As per How to specify the library version to use at link time? you can read the manual for ld with:man ld.

compiling openmp, macports gcc, and eclipse cdt

I am newbie in openmp. The following is the environment.
OS : Mac OSX Mavericks
Compiler : gcc (MacPorts gcc48 4.8.2_0) 4.8.2
IDE : Eclipse Kepler CDT plugin
I wrote the following openmp program
#include < stdio.h>
#include < omp.h>
int main()
{
#pragma omp parallel
{
int i=omp_get_thread_num();
printf("hello (%d)",i);
printf("world (%d)",i);
}
}
I compiled the above program and got the error that omp.h is not found and lgomp not found. Hence I added in the project properties an include path with /opt/local/lib/gcc48/gcc/x86_64-apple-darwin13/4.8.2/include and a library path /opt/local/lib/gcc48. The include path had the omp.h file and the library path had the file libomp.o.
I include the -fopenmp option in both the linker and the compiler option through project properties. It is compiling with gcc -I/opt/local/lib/gcc48/gcc/x86_64-apple-darwin13/4.8.2/include -O0 -g3 -Wall -c -fmessage-length=0 -fopenmp -MMD -MP -MF"src/OpenMPCourseExamples.d" -MT"src/OpenMPCourseExamples.d" -o "src/OpenMPCourseExamples.o" "../src/OpenMPCourseExamples.c" and linking with the command "gcc -L/opt/local/lib/gcc48 -fopenmp -o "OpenMPCourseExamples" ./src/OpenMPCourseExamples.o".
With the above command it compiles without an error but with a warning - "warning: unknown pragma ignored [-Wunknown-pragmas] #pragma omp parallel".
Also, I set an environment variable in the launch properties with OMP_NUM_THREADS=4. I ran the program that compiled with the above warning. I am getting only "hello (0)world (0)". I was under the impression that I should start four threads and should see the other outputs of "hello(1)world(1)hello(2)world(2)hello(3)world(3)" in some ordering as well. Now, here are my following questions.
Why am I getting the #pragma warning?
Is the compiler really detecting the openmp and building with openmp?
If everything is correct, why am I not seeing four different threads getting started?
The final steps that worked for openmp, macports gcc compiler, eclipse CDT in mac osx mavericks are.
Enable "Make ToolChain(s) Preferred" in Eclipse->Preference->C/C++->New C/C++ Project Wizard.
sudo port select --list gcc and set it sudo port select --set gcc with mp-gcc.
File->New Project->C Project (not C++) and create a hello world project.
In Project->Properties->C/C++ Build->Settings->Tool Settings set the following. (a) GCC C Compiler to /opt/local/bin/gcc-mp-4.8 (b)MAC OSX Linker to /opt/local/bin/gcc-mp-4.8
Build the hello world project and make sure, it compiles and runs successfully.
Include the open mp code. The code asked in the question of this page.
Go to again Project->Properties->C/C++ Build->Settings->Tool Settings set the following. (a) GCC Compiler ->Miscellaneous add -fopenmp (b) MacOSx Linker->Miscellaneous set -fopenmp
Build the code again.
The above steps worked good for me.
MacPorts configures the GCC build process with --program-suffix=-mp-${major} and therefore all compiler executables have the -mp-4.8 suffix. When you call gcc, you end up using Apple's Clang compiler, which does not support OpenMP and therefore does not recognise the -fopenmp option and #pragma omp ....
You have to do the following changes to the project settings:
Change the compiler command to gcc-mp-4.8
Change the linker command to gcc-mp-4.8
Remove the explicit specification of the include and library paths since the presence of -fopenmp adds them automatically.

Why does OpenBSD's G++ make system headers default to C linkage?

I am porting some code to OpenBSD 5.0 and I ran into this very strange problem.
My build settings use -isystem /usr/local/include. It is hard to remember but I believe I did that to avoid masses of compiler warnings from my use of -Wall on system types -- like BSD -- that install Boost to /usr/local/include. This seems to work great on FreeBSD.
So take the following program:
#include <boost/array.hpp>
int main()
{
return 0;
}
Then build it with:
c++ -O2 -pipe -isystem /usr/local/include -std=c++98 -o test test.cxx
On OpenBSD I discovered that I get:
In file included from /usr/include/g++/string:46,
from /usr/include/g++/stdexcept:44,
from /usr/local/include/boost/array.hpp:35,
from test.cxx:1:
/usr/include/g++/bits/stringfwd.h:48: error: template with C linkage
And it only gets worse from there.
I discovered that I can change the error messages by doing things such as:
#include <stdexcept>
But that only pushes the problem farther back. It is as if the compiler is wrapping every include file inside an extern "C" block.
So far, the only working method seems to be to change back to using -I /usr/local/include and accept the noise from -Wall -W.
The question is, why did OpenBSD do this? It has to be some kind of custom hack to GCC to treat system includes this way.
Recently came across the same issue when working with a freestanding cross compiler.
It seems G++ will do this when targeting "old" systems as indicated here:
http://tigcc.ticalc.org/doc/cpp.html#SEC9a
On very old systems, some of the pre-defined system header directories get even more special treatment. GNU C++ considers code in headers found in those directories to be surrounded by an extern "C" block. There is no way to request this behavior with a #pragma, or from the command line.
Hope this may provide some insight to future travelers here.

Resources