Linking C++ Code with 'Gcc' (Without G++)

Linking C++ code with 'gcc' (without g++)

You can link the standard c++ library with the -l flag to gcc:

gcc cplusplus.o -lstdc++ -o myexe

use gcc to directly compile to machine code without linking

I want to get gcc to compile c-code for me into x86-32 linux binary code, but without any librarys or so around it.

That means you write freestanding C code. (When the standard library is available, you have a hosted environment; when not, a freestanding one. )

To compile e.g. foo.c to an executable, foo, make sure it has a _start() function, and use

gcc -march=i686 -mtune=generic -m32 -ffreestanding -nostdlib -nostartfiles foo.c -o foo

The GNU toolchain uses the address of the _start symbol to encode the start address of the executable in the ELF file.

This answer is an actual real-world example for x86-64. For x86-32 (or any other architecture), you'll need to adjust the SYSCALL_ macros.


In a comment, OP explains they want a binary blob, instead of an ELF executable.

In this case, it is best to tell the compiler to generate a position independent executable. For example, 'blob.c':

void do_something(int arg)
{
/* Do something with arg, perhaps a syscall,
or inline assembly? */
}

void loop_something(int from, int to)
{
int arg;

if (from <= to)
for (arg = from; arg <= to; arg++)
do_something(arg);
else
for (arg = from; arg <= to; arg--)
do_something(arg);
}

void _start(void)
{
loop_something(2, 5);
do_something(6);
loop_something(5, 2);
do_something(1);
}

I do recommend declaring all functions except _start as static, to avoid any global offset table (GOT) or procedure linkage table (PLT) references (like <__x86.get_pc_thunk.bx> calls).

Compile this to an position independent executable using e.g.

gcc -march=i686 -mtune=generic -m32 -O2 -fPIE -ffreestanding -nostdlib -nostartfiles blob.c -o blob

strip it,

strip --strip-all blob

and dump the contents of the binary:

objdump -fd blob

In this output, there are two important lines:

start address 0x08048120

which tells the address of the _start symbol, and

080480e0 <.text>:

which tells the offset of the code, in hexadecimal. Subtract the former from the latter (0x08048120 - 0x080480e0 = 0x40 = 64) to get the offset of the start symbol.

Finally, dump the code into a raw binary file 'blob.raw' using

objcopy -O binary -j .text blob blob.raw

Does g++ work without gcc?

With a recent GCC, gcc (actually cc1 which is run by gcc) and g++ (actually cc1plus) -and so on for other GCC compilers, e.g. gfortran or even gdc ....- share a lot of (source) code together: the middle-end (where most optimizations happen) and the back-end. The difference is only the front-end layer of the compiler (the only layer being source language specific) which is less than 30% of the compiler.

You could customize the GCC compiler with plugins or with MELT. Your extensions would work on GCC internal representations (Gimple-s) and would work when compiling C, C++, Ada, Fortran, etc... Remember that GCC means Gnu Compiler Collection today

Actually the gcc program is able to compile C++ source code (and likewise g++ can compile C or Fortran code). However, they are not linking the same libraries.

Pass the -v flag to the gcc or g++ command to understand what they are running.


Here are two (mine) [CC-BY-SA] pictures -explaing GCC & MELT- illustrating this.

The three layers -front-end, middle-end, back-end- of the compiler:

with your plugin, or the MELT meta-plugin

Three layers of GCC

with a simplification: cc1 or cc1plus are generating assembler files, which is then translated by as started by gcc or g++

and

another view of the internals of cc1 or cc1plus,

which generates some assembler code

view of <code>cc1</code> or <code>cc1plus</code>

Compiling without libc

If you compile your code with -nostdlib, you won't be able to call any C library functions (of course), but you also don't get the regular C bootstrap code. In particular, the real entry point of a program on Linux is not main(), but rather a function called _start(). The standard libraries normally provide a version of this that runs some initialization code, then calls main().

Try compiling this with gcc -nostdlib -m32:

// Tell the compiler incoming stack alignment is not RSP%16==8 or ESP%16==12
__attribute__((force_align_arg_pointer))
void _start() {

/* main body of program: call main(), etc */

/* exit system call */
asm("movl $1,%eax;"
"xorl %ebx,%ebx;"
"int $0x80"
);
__builtin_unreachable(); // tell the compiler to make sure side effects are done before the asm statement
}

The _start() function should always end with a call to exit (or other non-returning system call such as exec). The above example invokes the system call directly with inline assembly since the usual exit() is not available.

C-library not linking using gcc/g++

Your library appears to have an API that assumes it will be called from C, not C++. This is important because C++ effectively requires that the symbols exported from a library have more information in them than just the function name. This is handled by "name mangling" the functions.

I assume your library has an include file that declares its public interface. To make it compatible with both C and C++, you should arrange to tell a C++ compiler that the functions it declares should be assumed to use C's linkage and naming.

A likely easy answer to test this is to do this:

extern "C" {
#include "customlibrary.h"
}

in your main.cpp instead of just including customlibrary.h directly.

To make the header itself work in both languages and correctly declare its functions as C-like to C++, put the following near the top of the header file:

#ifdef __cplusplus
extern "C" {
#endif

and the following near the bottom:

#ifdef __cplusplus
}
#endif

C Compilation error in Make but not GCC/G++

the link step of the compile/link sequence needs to be told '-lm' (lower case 'L') when

#include <math.h> 

is in the source code.

note ceil() and sqrt() prototypes are defined in math.h so should not have those prototypes overridden in the source code.

Linking C program with C++ library (GCC 4.5+)

It is because of linker's --as-needed option being used i.e. the library is not linked until a symbol is actually found in the source which is part of the library. You should move your source files before linking in the compilation command. You could try changing your Makefile rule program from $(CC) -L. -lrary -o $@ $< to $(CC) $< -L. -lrary -o $@. Or alternatively, you could pass --no-as-needed to the linker i.e. $(CC) -Wl,--no-as-needed -L. -lrary -o $@ $<. The first method is better suited to be used.

Hope this helps!



Related Topics



Leave a reply



Submit