Use 32bit shared library from 64bit application? - c

I have created a simple linux 32bit shared library(.so) for my rendering wrappers but i've hit a wall when i figured that i can only
use them through 32bit applications....................
This is how my code looks like:
RendIFace.h:
//Basic renderer interface
struct Renderer
{
int type;
...other things
};
GLRend.c:
#include "RendIFace.h"
struct Renderer* GLRendererCreate(int width,int height,int bytesPerPixel)
{
struct Renderer* rend = (struct Renderer*)malloc(sizeof(Renderer));
rend->type = GLR;
..other things
return rend;
}
SDLRend.c:
#include "RendIFace.h"
struct Renderer* SDLRendererCreate(int width,int height,int bytesPerPixel)
{
struct Renderer* rend = (struct Renderer*)malloc(sizeof(Renderer));
rend->type = SDLR;
..other things
return rend;
}
And i compile both as shared 32bit libraries(.so) and load them through the main application...
But now there is a big problem.My libraries are all 32bit and return 32bit pointers which means that i can't use them through
an 64bit application without rebuilding all the library code base(!!!).
So i would like to ask more experienced people : How do i handle this issue ? Is it possible to use just a single shared library for both architectures ???

You must be consistent. A 64-bit application can only use 64-bit libraries and a 32-bit application can only use 32-bit libraries. Both work; either choice is fine, and it's possible to compile the same code for both systems.
If you go for 'all 32-bit', use:
gcc -m32
If you go for 'all 64-bit', use:
gcc -m64
Sometimes, I'll tell make that the C compiler is gcc -m32 (or -m64) rather than just gcc to ensure the right value is used everywhere.

You can't do what you're asking. You must compile both the final executable and any libraries (both static and shared) for the same architecture.
On GCC, this can be done easily by passing the command line argument -m32 either directly in the command line or by adding it CCFLAGS in your Makefile.
While it is possible to run x86 code on a x86_64 operating system (you just need to have all the right libraries and their respective recursive dependencies), you cannot, in one executable or in one address space, combine x86 and x86_64 binaries.

Related

Are there specific compiler flags to use gcc sync-builtins when cross-compiling for arm?

I'm trying to cross-compile a program that uses gcc builtins, specific __sync_val_compare_and_swap, __sync_add_and_fetch and sync_sub_and_fetch.
Compiling works, but the linker is showing me the undefined reference errors.
For example:
memory_layout.c:(.text.memory_uniqueid+0x1c): undefined reference to '__sync_val_compare_and_swap_4'
memory_layout.c:(.text.ipc_counter+0x18): undefined reference to '__sync_add_and_fetch_4'
I'm using the st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3 toolchain that comes with eclipse and SW4STM32. My host machine is a 64-Bit Linux Mint. The program is build with CMake.
The needed functions are defined in the toolchain file lib/gcc/arm-none-eabi/7.3.1/plugin/include/sync-builtins.def.
I've searched for similar errors but the provided solution (use -march=i486) but this didn't help.
Another workaround I found is to compile the needed functions in an own library (http://vincesoft.blogspot.com/2012/04/how-to-solve-undefined-reference-to.html) but this seems to be for older gcc versions.
I also tried to manually link libgcc (that comes with the toolchain) but without success. The used commands are
add_library(GCC_LIB STATIC IMPORTED /home/toolchains/st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3/lib/gcc/arm-none-eabi/7.3.1/libgcc.a)
target_link_libraries(${PROJECT_NAME} ${GCC_LIB})
the error is caused in the following function
static inline unsigned int atomic_inc(unsigned int v)
{
/* atomic load, modify, store */
return __sync_add_and_fetch(v, 1);
}
Do I need to provide some special compiler flags or defines so the builtin functions can be linked?
As #KamiCuk pointed out I had to implement the needed functions by myself.
The disable_intterrups() and enable_interrupts() function in his comment are os dependent. As I was compiling for Freertos I used portENTER_CRITICAL and portEXIT_CRITICAL.
The finale solution for __sync_add_and_fetch_4 looked like this:
__sync_add_and_fetch_4(unsigned *v, unsigned add, ...) {
portENTER_CRITICAL();
const unsigned ret = *v;
*v += add;
portEXIT_CRITICAL();
return ret; }
Some of the atomic operations are already provided by FreeRTOS headers (atomic.h).

Porting 64bit code to 32bit machine

I have seen many people asking porting issues from 32bit to 64bit machine. But is it not common to port code written on 64bit to 32bit. I am trying to port a plugin from 64bit to 32bit in C,but facing similar issues in cases like storing void * to 64bit integers and vice versa.
Whats should be approach in changing the code such that same code works on both(i386 & x86_64) machines? I don't think it make sense to use uint64_t * on a 32 bit machine in place of void* which is 32bit? Does some generalized approach exists for such cases?
Pointers should never be stored in fixed-size integers. If you need to store a pointer in an integer type, the correct type is uintptr_t, but you really should not be storing pointers in integer objects at all. However, there's no real harm in using an integer type that's too large; it will just waste a little bit of memory. So if storing pointers in uint64_t is the only issue in your code, it should work fine compiled for 32-bit targets.
As you know, You can write one source code for both 32bit and 64bit architectures with a series of "#define", "#ifdef" etc which are pre-processor directives. You need to compile the source once for 32bit and 64bit each. This can be something like this.
test.c sample code
#ifdef ARCH_64
typedef UINT unit64_t;
#else
typedef UINT unit32_2;
UINT *my_uint_ptr;
$ gcc -m32 test.c
$ gcc -m64 -DARCH_64 test.c

Where do i get BIOS.h file, to import in Mingw?

Mingw don't have BIOS.h file by default. And i'm doing system programming by using netbeans IDE and a third party tool mingw. . ?
Can any one helps me, where do i get that file?
This is the code.
#include<stdio.h>
#include<BIOS.H>
#include<DOS.H>
char st[80] ={"Hello World$"};
void main()
{
_DX = (unsigned int) st;
_AH = 0x09;
geninterrupt(0x21);
}
Nowhere, you don't.
Those header files (dos.h and bios.h) are from 16-bit DOS compilers such as Turbo C or Open Watcom C. MinGW is a 32-bit compiler for Windows. As such, even if you get these header files, they will be useless because:
they are incompatible with gcc
they also need counterpart libraries because the headers themselves do not contain definitions of things like geninterrupt()
DOS interrupt services (int 21h) are not available to Win32 programs
Further, gcc does not support variables aliasing to CPU registers (e.g. _DX, _AH).
You either need to use the appropriate 16-bit DOS compiler or write a Windows program using functionality available from gcc and Win32 API.
Do you really need it? It's been obsoleted a hundred or so times. But from what I've heard, some older Turbo C versions might have it. You can also try out http://www.sandroid.org/TurboC/ , but they say the file might not have all the functions.

Is executable file generated after compiling in C can be copied and run on any differnet OS(UNIX)?

I am a java programmer, but i have few things to be done in C. So, i started with a simple example as below. If i have compiled it and generate a executable file (hello), can i run the executable file (hello) in any unix platform without the original file (hello.c)? And also is there a way to read the data from executable file means, decompile the executable file to original file (hello.c)?
[oracle#oracleapps test]$ cat hello.c
#include <stdio.h>
int main(){
int i,data =0;
for(i=1;i<=64;i+=1){
data = i*2;
printf("data=%d\n",data);
}
return 0;
}
To compile
gcc -Wall -W -Werror hello.c -o hello
You can run the resulting executable on platforms that are ABI-compatible with the one which you have compiled the executable for. ABI-compatibility basically means that the same physical processor architecture and OS-interfaces (plus calling convention) is used on two (possibly different) OSes. For example, you can run binaries compiled for Linux on a FreeBSD system (with the same processor type), because FreeBSD includes Linux ABI-compatibility. However, it may not be possible to run a binary on all other types of Unices, unless some hackery is done. For example, you can't run Mac OS X applications on linux, however this guy has a solution with which it's possible to use some OS X command line tools (including the GCC compiler itself) on Linux.
Reverse engineering: there are indeed decompilers which aim to generate C code from machine code, but they're not (yet) very powerful. The reason for this is they're by nature extremely hard to write. Machine code patterns have to be recognized, and even then you can't gather all the original info. For example, types of loops, comments and non-static local variable names and most of the types are all gone during the compilation process. For example, if you have a C source file like this:
int main(int argc, char **argv)
{
int i;
for (i = 0; i < 10; i++)
{
printf("I is: %d\n", i); /* Write the value of I */
}
return 0;
}
a C decompiler may be able to reconstruct the following code:
int main(int _var1, void *_var2)
{
int _var3 = 0;
while (_var3 < 10)
{
printf("I is: %d\n", _var3);
_var3 = _var3 + 1;
}
return 0;
}
But this would be a rather advanced decompiler, such as this one.
You can't run the executable on any platform.
You can run the executable on other machines (or this one) without the .c file. If it is the same OS / Distro running on the same hardware.
You can use a de-compiler to disassembler to read the file and view it as assembly or C-- they won't look much like the original c file.
The compiled file is pure machine code (plus some metadata), so it is self-sufficient in that it does not require the source files to be present. The downside? Machine code is both OS and platform-specific. By platform, we usually mean just roughly the CPU's instruction set, i.e. "x86" or "PowerPC", but some code compiled with certain compiler flags may require specific instruction set extensions. The OS dependence is caused not only by different formats for executable files (e.g. ELF as opposed to PE), but also by use of OS-specific services, or common OS services in an OS-specific manner (e.g. system calls). In addition to that, almost all nontrivial code depends on some libraries (a C runtime library at least), so you probably won't be able to run an executable without having the right libraries in compatible versions. So no your executable likely won't run on a 10 year old proprietary UNIX, and may not run on different Linux distributions (though with your program there's a good chance it does, because it likely only depends on glibc).
While machine code can be easily disassembled, the result is very low-level and useless to many people. Decompilation to C is almost always much harder, though there are attempts. The algorithms can be recovered, simply because they have to be encoded in the machine code somehow. Assuming you didn't compile for debugging, it will never recover comments, formatting, variable names, etc. so even a "perfect" decompiler would yield a different C file from the one you put in.
No ... each platform may have a different executable format requirements, different hardware architectures, different executable memory layouts determined by the linker, etc. A compiled executable is "native" to it's currently compiled platform, not other platforms. You can cross-compile for another architecture on your current machine though.
For instance, even though they may have many similarities, a compiled executable on Linux x86 is not guaranteed to run under BSD, depending on it's flavor (i.e., you could probably run it under FreeBSD but typically not OSX's Darwin version of BSD even thought both machines may have the same underlying hardware architecture). You also couldn't compile something on a SGI MIPS machine running IRIX and run it on a Sun SPARC running Solaris.
With C programs, the program is tied to the environment it was compiled for (which is usually the same as the platform it was compiled on, unless you are cross-compiling). You could copy something built for one version of Linux (and a particular hardware architecture) to another machine with the same archtecture running the same version of Linux, and you'll be fine. You can often get away with running it on a related version of Linux. But you won't get x86/64 code to run on a IA32 machine, nor on a PPC machine, nor on a SPARCmachine. You can likely get IA32 code to run on an x86/64 machine, if the basic O/S is sufficiently similar. And you may or may not be able to get something compiled for Debian to run under RedHat or vice versa; it depends on which libraries your program uses.
Java avoids this by having a platform-neutral byte code program that is compiled, and a platform specific JVM (JRE) to run it on each platform. This WORM (Write Once, Run Many) behaviour was a key selling point for Java.
Yes, you can run it on any unix qemu runs on. This is pretty comparable to java programs, which you can run on any unix the jvm runs on...

Is the -mx32 GCC flag implemented (correctly)?

I am trying to build a program that communicates with a 32-bit embedded system, that runs on a Linux based x86_64 machine (host). On the host program I have a structure containing a few pointers that reflects an identical structure on the embedded system.
The problem is that on the host, pointers are natively 64-bits, so the offset of the structure members is not the same as in the embedded system. Thus, when copying the structure (as memcpy), the contents end up at the wrong place in the host copy.
struct {
float a;
float b;
float *p;
float *q;
} mailbox;
// sizeof(mailbox) is 4*4=16 on the embedded, but 2*4+2*8=24 on the host
Luckily, I found out here that gcc has an option -mx32 for generating 32-bit pointers on x86_64 machines. But, when trying to use this, I get an error saying:
$ gcc -mx32 test.c -o test.e
cc1: error: unrecognized command line option "-mx32"
This is for gcc versions 4.4.3 and 4.7.0 20120120 (experimental).
Why doesn't this option work? Is there a way around this?
EDIT: Accrding to the v4.4.7 manual, there was no -mx32 option available, and this is true up to v4.6.3. OTOH, v4.7.0 does show that option, so it may be that the Jan-20 version I am using is not the final one?!
Don't do this. First, x32 is a separate architecture. It's not merely a compiler switch. You need an x32 version of every library you link against to make this work. Linux distros aren't yet producing x32 versions, so that means you'll be either linking statically or rolling your own library environment.
More broadly: that's just asking for trouble. If your structure contains pointers they should be pointers. If it contains "32 bit addresses" they should be a 32 bit integer type.
You might need a newer version of binutils
Though I think gcc 4.8 is recommended
But in general you need a kernel compiled multilib with it: https://unix.stackexchange.com/questions/121424/linux-and-x32-abi-how-to-use

Resources