c binary file greater than source file [duplicate] - c

This question already has an answer here:
size of executable files?
(1 answer)
Closed 7 years ago.
I have a c source file with name simple.c (file size 68 bytes) and I compiled it using gcc. The output binary file size is 7151 bytes.
C Source code:
int main()
{
int a = 10;
int b = 34;
int c = a + b;
return c;
}
I haven't included any header files.
I don't know, how does the C binary file becomes bigger than the source file. Can anyone please explain?
test#test-desktop:~/Desktop/c$ ls -l
total 4
-rw-rw-r-- 1 test test 68 Jul 15 15:04 simple.c
test#test-desktop:~/Desktop/c$ gcc simple.c
test#test-desktop:~/Desktop/c$ ls -l
total 12
-rwxrwxr-x 1 test test 7151 Jul 15 15:04 a.out
-rw-rw-r-- 1 test test 68 Jul 15 15:04 simple.c
The above is the terminal output.

You have a certain one-time overhead even without including anything. There is code running before main() (which is setting up stdin, stdout, and stderr, signal handler tables etc.), and code running after that function returns (e.g. checking for anything registered with atexit() and similar things). This is called the C runtime, traditionally located in crt0.o, which is linked into any executable.

It'll be the debug and symbol information. Optimize and strip it:
Use gcc -Os to optimize for smallest size.
Use strip a.out to remove the symbols and debug info.
There are also the CRT startup files providing the bulk of your binary that process argc, argv etc and setup your environment. You can opt out of those using -nostartfiles but you probably don't want to do that.

Related

OCaml as C library, hello world example

I wish to call OCaml code through C++ by compiling OCaml to a static or shared library that contains a C interface. This page seems to explain how to create a C interface for OCaml. But how do I do it and compile it? And how do I obtain the .h file to load in my C++ code?
Also, could someone explain to be this part:
The OCaml runtime system comprises three main parts: the bytecode
interpreter, the memory manager, and a set of C functions that
implement the primitive operations. Some bytecode instructions are
provided to call these C functions, designated by their offset in a
table of functions (the table of primitives).
I thougth OCaml could be compiled to native machine language. Why it is compiled to bytecode and interpreted at runtime? Is it always like that, or only for OCaml libraries compiled with C interface?
Most of that page describes how to call C from OCaml. You want to do the reverse, which is described in Advanced Topics: callbacks from C to OCaml, closer to the bottom of the page.
When you do native compilation there is no bytecode involved, just as you say. The native compiler (ocamlopt) produces ordinary object (.o in Unix) files and extra files containing OCaml metadata.
If you look at Advanced Example with callbacks, you'll see an example where the main program is in C, with calls to two functions defined in OCaml. Things should work similarly in C++. (I have only done this in C myself, however.)
Update
Here is the worked-out example using the code from Advanced example with callbacks. I am running this code on Ubuntu 18.04.4 (x86_64).
The OCaml code looks like this:
$ cat mod.ml
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 1)
let format_result n = Printf.sprintf "Result is: %d\n" n
let () = Callback.register "fib" fib
let () = Callback.register "format_result" format_result
Compile this code and ask for a complete object file:
$ ocamlopt -output-obj -o bigmod.o mod.ml
Rename the C code to modwrap.cc. (The code is given in the OCaml manual section.)
$ head -6 modwrap.cc
#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
int fib(int n)
Note that the OCaml include files are conditionalized as to whether they're being included from C or C++ (as are almost all header files these days).
The main function from the OCaml manual section is also valid C++; rename it to main.cc:
$ head -7 main.cc
#include <stdio.h>
#include <caml/callback.h>
extern int fib(int n);
extern char * format_result(int n);
int main(int argc, char ** argv)
Now compile and link everything:
$ g++ -c modwrap.cc
$ g++ -o myprog -I $(ocamlopt -where) \
main.cc modwrap.o bigmod.o $(ocamlopt -where)/libasmrun.a -ldl
$
Now run the program
$ ./myprog
fib(10) = Result is: 89
There is no automatic generation of header files. In this example the extern lines of main.cc are the header file in essence. If you want a header file you'll have to write something like this yourself.
Update 2
Here are the commands for creating an actual static library containing the OCaml functions and their wrappers. This assumes that you have done the compiles above to create bigmod.o and modwrap.o:
$ cp $(ocamlopt -where)/libasmrun.a libmyoc.a
$ ar r libmyoc.a bigmod.o modwrap.o
Now you can use this library in your C++ code (represented by main.cc):
$ g++ -o myprog -I $(ocamlopt -where) main.cc -L . -lmyoc -ldl
$ ./myprog
fib(10) = Result is: 89
Update 3
(I updated the above commands to work on Unbuntu.)

Compiling against gpsd on OpenWRT - linking fails

I'm trying to compile a tool that uses gps.h, but my compilation seems to fail each time when it tries to link to libgps. The error message I receive is:
/opt/openwrt-sdk/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/bin/../lib/gcc/arm-openwrt-linux-muslgnueabi/7.3.0/../../../../arm-openwrt-linux-muslgnueabi/bin/ld: cannot find -lgps
This is the command I'm compiling with:
arm-openwrt-linux-gcc -o ./bin/eagle src/main.c -I./src -I/opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/include -static -L/opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/lib -lpthread -lgps
Basic code for reference:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gps.h>
int main(void)
{
int rc;
struct gps_data_t gps_data;
if ((rc = gps_open("localhost", "2947", &gps_data)) == -1)
{
printf("code: %d, reason: %s\n", rc, gps_errstr(rc));
return 1;
}
gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);
return 0;
}
And some directory listings in my toolchain - as far as I can tell, libgps has compiled successfully:
# ls -lah /opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/include/ | grep gps
-rw-rw-r-- 1 root root 80K Sep 7 2017 gps.h
# ls -lah /opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/lib/ | grep gps
lrwxrwxrwx 1 root root 16 Oct 17 18:46 libgps.so -> libgps.so.23.0.0
lrwxrwxrwx 1 root root 16 Oct 17 18:46 libgps.so.23 -> libgps.so.23.0.0
-rwxr-xr-x 1 root root 101K Oct 17 18:46 libgps.so.23.0.0
Many thanks in advance for any help.
Your link command line contains '-static', which prevents linking against *.so shared libraries (aka shared objects, hence 'so'), but still permits linking against *.a static-link libraries (aka archives).
See: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
In the directory whose contents you listed, and which the link command line is directed towards using the '-L' flag, there is a shared object libgps.so, but there is no static-link library libgps.a .
This leaves the linker no way to satisfy the link-time dependency on libgps. The only way to satisfy it, using libgps.so, has been disabled using '-static'.
To fix, either:
Modify the tool's compile recipe, so as to remove '-static' from the link command line, so as to enable use of the shared object, or
Modify gpsd's compile recipe, so as to cause a static-link library libgps.a to built, either in addition to or instead of libgps.so.

Mac C program crashes on string initializer

I'm trying to build somebody else's C program on my Mac, using command line tools to build a command line program. Straightforward C program, should be as simple as anything. But I'm getting really strange memory access errors during declaration and initialization of variables in main(), so early that I really don't see how I could have messed anything up. This is basic core C language material, how it could be failing really beats me.
Ken$ gcc -std=c99 -ggdb srtm2stl.c geometry.c stlwriter.c -o srtm2stl
Ken$ gdb ./srtm2stl
. . .
(gdb) run
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00007fff5b74f6c0
0x0000000100000e37 in main (argc=10, argv=0x7fff5fbff990) at srtm2stl.c:195
195 char SolidName[132] = {' '}; // Optional name for solid (text format STL files)
(gdb) list 195
190 int main(int argc, char *argv[])
191 {
192 FILE *in = NULL; // input file
193 FILE *out = NULL; // output file
194
195 char SolidName[132] = {' '}; // Optional name for solid (text format STL files)
196 // char SolidName[132]; // Optional name for solid (text format STL files)
197 int Verbose = 0; // Flag: Verbose
The only thing that comes to mind is that it's building in 64-bit mode, and I've never built a 64 bit program before. Are there other command line arguments that need to be given to gcc to make this work properly? Or other theories?
Note line 196. If I comment out line 195 and use 196 instead, we get a little farther before a similar crash:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00007fff5b74f8e0
main (argc=1, argv=0x7fff5fbffa20) at srtm2stl.c:216
216 unsigned int i = 0;
(gdb) list 216
214 long Bias = 0;
215 short grid[MAXROWS][MAXCOLS]; // Array to hold the elevations
216 unsigned int i = 0;
217 short stemp;
Seems like there's something about arrays. MAXROWS and MAXCOLS are each 6001 in this build, that shouldn't be overwhelming with modern memory sizes. Right?
OSX 10.7.5, gcc version i686-apple-darwin10-llvm-gcc-4.2,
GNU gdb 6.3.50-20050815
extern short grid; // global outside the main
grid = malloc(sizeof(short) *6000*6000) // inside the main..
It seems you are using multiple files.. If you are using any header, then you can also extern the grid and use it in other places.. Detailed info can only be given once we can see the implementation.. Moreover if you are using OSX I will suggest you to use lldb instead of gdb.. Because gdb on Mac may have a code signing problem
WhozCraig got it. (See his comment.) I was trying to allocate more on the stack than the stack could handle. Moving the array to global storage fixed everything.

C file not reading properly

When I run the following command in the command terminal: gcc practice.c temp.txt
I get the following error:
/usr/local/binutils/2.21/bin/ld:temp.txt: file format not recognized; treating as linker script
/usr/local/binutils/2.21/bin/ld:temp.txt:1: syntax error
collect2: ld returned 1 exit status
Here is my C code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LEN 1024
int main(int argc, char **argv) {
FILE *file;
char line[MAX_LEN];
float value = 0;
file = fopen(argv[1], "r");
while (fgets(line, MAX_LEN, file) != NULL) {
sscanf(line, "%f", &value);
printf("%f\n", value);
}
fclose(file);
return 0;
}
Basically I am trying to read numbers in a file and just print them out. Very simple.
For example, temp.txt will just be something like:
10
26
27
52
242
(these numbers should be in a column)
and so forth.
You may need some explanation about what gcc really is, gcc is used to translate your code into a runnable program, it's a sort of translator for code to executable instruction for your computer.
You do not need to compile the text file, you first need to compile your program :
gcc practise.c -o your_binary_name
then launch it with your file in parameter :
./your_binary_name temp.txt
use gcc to compile the executable, and then run the executable on the input file afterwards. You get an error b/c gcc is trying to compile your test.txt as C source code.
So:
gcc practice.c -o practice
./practice test.txt
C is a compiled not an interpreted language. GCC does not run the code as say Python or other scripting languages can for example. GCC rather translates the C source code to native machine code that when linked to the target runtime to create an executable is then separately and directly loaded and executed by the operating system without support from GCC at all.

Why does gdb show my code with macros even after I manually run the preprocessor?

Sorry if this question is poorly phrased, but it's a weird problem and I'm not sure entirely how to explain it. I wrote some stupid code involving macros that had a stupid error, but even though I solved the problem, gdb didn't help very much. I thought the problem might be in how I wrote the macros (it wasn't), so I used the -E flag so I could inspect the code and debug it without the macros. Then this happened:
/media/sf_Mint-Shared/C $ clang switch.c -E > switch_e.c
/media/sf_Mint-Shared/C $ clang switch_e.c -g -O0 -o switch
/media/sf_Mint-Shared/C $ gdb switch
[snip]
(gdb) run
Starting program: /media/sf_Mint-Shared/C/switch
Enter your favorite fruit: apple
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b6f2f2 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) l
6 #define SWITCH(t) strcpy(switch_str, t);
7 #define CASE(c, d) if (!strcmp(switch_str, (c))) {d} else
8 #define ELSE(d) {d}
9 #define ENDSWITCH() switch_str = NULL;
10
11 int main()
12 {
13 char fruit[20];
14
15 printf("Enter your favorite fruit: ");
(gdb) l 26
21 scanf("%s", fruit);
22 to_lower(fruit);
23
24 SWITCH(0, fruit)
25 CASE(0, "apple", puts("Apples are delicious!");)
26 CASE(0, "pear", puts("Pears are alright");)
27 CASE(0, "banana", puts("Ew, bananas are gross");)
28 ELSE(puts("Sorry, I don't know that fruit.");)
29 ENDSWITCH(0)
30
In case it isn't obvious, the macros are still present, despite the fact that I compiled the executable from the fully preprocessed source. Here's the (truncated) code that went into the processor:
// Includes truncated
static char *switch_str;
int main()
{
char fruit[20];
printf("Enter your favorite fruit: ");
scanf("%s", fruit);
strcpy(switch_str, fruit);
if (!strcmp(switch_str, ("apple"))) {puts("Apples are delicious!");} else
if (!strcmp(switch_str, ("pear"))) {puts("Pears are alright");} else
if (!strcmp(switch_str, ("banana"))) {puts("Ew, bananas are gross");} else
{puts("Sorry, I don't know that fruit.");}
switch_str = ((void *)0);
return 0;
}
How are the original macros persisting even after preprocessing and how can I debug with them expanded?
The gcc preprocessor inserts #line directives to be able to correlate preprocessed lines to the original line. The gcc compiler uses these directives, both to produce error messages and for debugging information. Consequently, gdb is instructed to look at the original file for source information, even if you run the preprocessor manually.
You can use the -P option to cpp in order to suppress #line directives.

Resources