Normally when using gdb I can stop execution and rebuild the executable and restart without loosing my breakpoints. When I try this with an executable that has a statically linked library I get an error stating that I cannot open the executable file during the build.
A concrete example:
The library files:
libtest.h:
int square(int a);
libtest.c:
int square(int a) {
return a * a;
}
The library is compiled with:
gcc -g -c libfile.c
ar rcs libtest.a libfile.o
Main file a.c contains:
#include <stdio.h>
#include <stdlib.h>
#include "libfile.h"
int main() {
printf( "2 squared is %d\n", square(2) );
return 0;
}
The project is compiled and linked like this:
gcc -g -c a.c
gcc a.o -g --static -L. -ltest -o gdb_test
If I load the resulting file gdb_test into gdb it doesn't matter if it is running it not. As long is gdb is open a subsequent build will fail during the link step:
/usr/bin/ld: cannot open output file gdb_test: Permission denied
Is there a way around this? I would like to be able to work with gdb without having to restart it and loose my breakpoints.
It is probably a matter of versions of GDB or GCC; it works for me:
% gcc -g -c libtest.c
gcc -g -c libtest.c
% ar rcs libtest.a libtest.o
ar rcs libtest.a libtest.o
% gcc -g -c -Wall a.c
gcc -g -c -Wall a.c
% gcc -Wall -g a.o -L. -ltest -o gdb_test
gcc -Wall -g a.o -L. -ltest -o gdb_test
% ./gdb_test
2 squared is 4
% gdb ./gdb_test
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/basile/tmp/gdb_test...done.
(gdb) r
r
Starting program: /home/basile/tmp/gdb_test
2 squared is 4
[Inferior 1 (process 12271) exited normally]
(gdb) quit
quit
% gcc -v
gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc-4.6.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.2-9'
--with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr
--program-suffix=-4.6 --enable-shared --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc
--with-arch-32=i586
--with-tune=generic --enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.2 (Debian 4.6.2-9)
My system is Debian/Sid/amd64. GCC is (Debian 4.6.2-9); ld = binutils = ar is GNU gold (GNU Binutils for Debian 2.22); GDB is GNU gdb (GDB) 7.3.50.20111117-cvs-debian; Gnu Libc is (Debian EGLIBC 2.13-24). Kernel is Linux version 3.1.0-1-amd64 (Debian 3.1.5-1)
And I am able to recompile the program from inside gdb and to run it:
% gdb ./gdb_test
gdb ./gdb_test
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/basile/tmp/gdb_test...done.
(gdb) shell gcc -g -c -Wall a.c
shell gcc -g -c -Wall a.c
(gdb) r
r
Starting program: /home/basile/tmp/gdb_test
2 squared is 4
[Inferior 1 (process 12335) exited normally]
(gdb) shell gcc -Wall -g a.o -L. -ltest -o gdb_test
shell gcc -Wall -g a.o -L. -ltest -o gdb_test
(gdb)
(gdb) r
r
`/home/basile/tmp/gdb_test' has changed; re-reading symbols.
Starting program: /home/basile/tmp/gdb_test
2 squared is 4
[Inferior 1 (process 12346) exited normally]
(gdb) quit
quit
%
/usr/bin/ld: cannot open output file gdb_test: Permission denied
This is unlikely to be related to either GDB or ld (or their versions), and is most certainly not related to your use of archive library.
Much more likely this is happening because you are using some "strange" filesystem. Perhaps you are using NTFS or CIFS mount? What does df . say?
Related
I am trying to follow along with this course (https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-s096-effective-programming-in-c-and-c-january-iap-2014/getting-started/), and running into some compilation problems.
It suggests using gcc, make, and the Makefile below.
I don't know if the error message I am getting has to do with something in the C source code (seems unlikely), or with the way I have configured the gcc options.
$ gcc-8 -v
Using built-in specs.
COLLECT_GCC=gcc-8
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/8.1.0/libexec/gcc/x86_64-apple-darwin17.5.0/8.1.0/lto-wrapper
Target: x86_64-apple-darwin17.5.0
Configured with: ../configure --build=x86_64-apple-darwin17.5.0 --prefix=/usr/local/Cellar/gcc/8.1.0 --libdir=/usr/local/Cellar/gcc/8.1.0/lib/gcc/8 --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-8 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --enable-checking=release --with-pkgversion='Homebrew GCC 8.1.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-nls
Thread model: posix
gcc version 8.1.0 (Homebrew GCC 8.1.0)
$ gmake -v
GNU Make 4.2.1
Built for x86_64-apple-darwin17.0.0
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ cat Makefile
CC:=gcc-8
CFLAGS:=-O0 -g -std=c99 -Wall -Wextra -Wshadow -pedantic –Werror
CXXFLAGS:=-O0 -g -std=c++11 -Wall -Wextra -Wshadow -pedantic -Weffc++ -Werror
$ cat nothing.c
int main (void){
return 0;
}
$ gmake nothing
gcc-8 -O0 -g -std=c99 -Wall -Wextra -Wshadow -pedantic –Werror nothing.c -o nothing
gcc-8: error: –Werror: No such file or directory
gmake: *** [<builtin>: nothing] Error 1
The problem here is that in your makefile the dash before Werror isn't a standard dash, it's a unicode dash (code 8211)
-pedantic –Werror
if you look closely, the lengths differ slightly. Sometimes word processors or e-mail clients switch dashes for some cosmetic reason...
The consequence is that the options parser sees that as a file, not an option, and tries to open it to compile it.
The fix is obvious when you know that: use the proper dash in CFLAGS (the dash is ok in CPPFLAGS):
-pedantic -Werror
This question already has answers here:
How to make a linux shared object (library) runnable on its own?
(2 answers)
Closed 5 years ago.
In glibc (and also EGLIBC I believe), the libc.so library has a main() method:
$ /lib/i386-linux-gnu/libc.so.6
GNU C Library (Debian GLIBC 2.19-18+deb8u1) stable release version 2.19, by Roland McGrath et al.
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.4.
Compiled on a Linux 3.16.7 system on 2015-08-30.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.
Now I want to do the same with the following minimalistic example (i. e. I want my own SO to also have a main()):
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello, World!\n");
return 0;
}
Linking as a regular executable:
$ gcc -g -O0 -Wall -c test.c
$ gcc -o test test.o
$ ./test
Hello, World!
Now linking as a shared object:
$ gcc -g -O0 -Wall -c test.c
$ gcc -shared -o libtest.so test.o
$ ./libtest.so
Segmentation fault
nm shows that main symbol is present (000004f5 T main)
When debugging, gdb doesn't show any meaningful backtrace.
Adding -fpic or -fPIC to the gcc command line doesn't help.
What am I doing wrong?
the libc.so library has a main() method
No, the implementation of C library of gcc has an entry point not a main symbol.
You can find an example of how to do this here.
If I have the following program written in C (compiled with GCC on Debian 8.7), I am able to call atexit() as you would expect:
#include <stdlib.h>
void exit_handler(void) {
return;
}
int main () {
atexit(exit_handler);
return 0;
}
And when I compile and run it:
$ gcc test.c
$ ./a.out
Outputs nothing, just as you would expect. In fact, when I run ldd, I get:
$ ldd a.out
linux-vdso.so.1 (0x00007fffbe592000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe07d3a8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe07d753000)
However, libc does not seem to have any symbols for atexit, amd only has__cxa_atexit and __cxa_threaded_atexit_impl:
$ nm --dynamic /lib/x86_64-linux-gnu/libc.so.6 | grep 'atexit'
0000000000037d90 T __cxa_atexit
0000000000037fa0 T __cxa_thread_atexit_impl
As you would then expect, if I try to link to libc dynamically, I cannot actually call atexit(), such as in the following Racket program which links to libc and tries to find atexit:
#lang racket
(require ffi/unsafe)
(get-ffi-obj 'atexit (ffi-lib "libc" '("6")) (_fun (_fun -> _void) -> _int))
Giving the output:
$ racket findatexit.rkt
ffi-obj: couldn't get "atexit" from "libc.so.6" (/lib/x86_64-linux-gnu/libc.so.6: undefined symbol: atexit)
What I want to know here is:
If libc does not have any symbol for atexit on Linux, why can I still call it from a C program?
Is there any way I can call atexit or a similar function dynamically on Linux?
(I should note that atexit does appear to be a symbol on OS X, so its just Linux that seems unusual here.)
Edit:
At the suggestion of #Jonathan, I also ran:
$ gcc -c test.c
$ nm test.o
U atexit
0000000000000000 T exit_handler
0000000000000007 T main
Which seems to indicate the atexit symbol is there somewhere, but it does not appear in any of the libraries ldd is showing.
I did some poking around on a Centos 7 virtual machine, and I think I found it — but it was anything but obvious!
Found it!
In /usr/lib64/libc_nonshared.a:
$ nm /usr/lib64/libc_nonshared.a | grep -i atexit
atexit.oS:
0000000000000000 T atexit
U __cxa_atexit
$
Why look in that library? Good question — and a long story. Are you sitting comfortably? Then I'll begin…
Steps taken to get there
Use the test.c code from the question.
Compile it with gcc -v test.c:
$ gcc -v test.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v test.c -quiet -dumpbase test.c -mtune=generic -march=x86-64 -auxbase test -version -o /tmp/ccPHTer7.s
GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-11) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-11), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=96 --param ggc-min-heapsize=124992
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
End of search list.
GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-11) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-11), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=96 --param ggc-min-heapsize=124992
Compiler executable checksum: 356f86e67978d665416e07d560c8ba0d
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/cc5WHEA4.o /tmp/ccPHTer7.s
GNU assembler version 2.25.1 (x86_64-redhat-linux) using BFD version version 2.25.1-22.base.el7
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/cc5WHEA4.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
$
The interesting part is the collect2 command line at the end. Written with one argument per line, that is:
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2
--build-id
--no-add-needed
--eh-frame-hdr
--hash-style=gnu
-m
elf_x86_64
-dynamic-linker
/lib64/ld-linux-x86-64.so.2
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64
-L/lib/../lib64
-L/usr/lib/../lib64
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..
/tmp/cc5WHEA4.o
-lgcc
--as-needed
-lgcc_s
--no-as-needed
-lc
-lgcc
--as-needed
-lgcc_s
--no-as-needed
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
So, there are a bunch of cr*.o files, plus three libraries: -lc, -lgcc and -lgcc_s to look for, and a bunch of directories to look in:
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5, -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64, -L/lib/../lib64, -L/usr/lib/../lib64, -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../... The /tmp/cc5WHEA4.o is the object file created from test.c.
Applying some clean-up code to the path names, and then using ls to help find the libraries yields a list of files to examine further:
/lib64/ld-linux-x86-64.so.2
/usr/lib64/crt1.o
/usr/lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o
/usr/lib64/crtn.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcc_s.so
/usr/lib64/libgcc_s.so.1
/lib64/libgcc_s.so.1
/usr/lib64/libgcc_s.so.1
/usr/lib64/libc.so
/usr/lib64/libc.so.6
/lib64/libc.so
/lib64/libc.so.6
/usr/lib64/libc.so
/usr/lib64/libc.so.6
That list of files was saved in a file yy (unimaginative name), and then used in:
$ nm -o $(<yy) | tee nm.log | grep -i atexit
nm: _trampoline.o: no symbols
nm: __main.o: no symbols
nm: _ctors.o: no symbols
nm: /usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcc_s.so: no symbols
nm: /usr/lib64/libgcc_s.so.1: no symbols
nm: /lib64/libgcc_s.so.1: no symbols
nm: /usr/lib64/libgcc_s.so.1: no symbols
nm: /usr/lib64/libc.so: File format not recognized
/usr/lib64/libc.so.6:00000000003bcc00 b added_atexit_handler.9157
/usr/lib64/libc.so.6:0000000000038c90 T __cxa_atexit
/usr/lib64/libc.so.6:0000000000038c90 t __cxa_atexit_internal
/usr/lib64/libc.so.6:00000000003b6838 d __elf_set___libc_atexit_element__IO_cleanup__
/usr/lib64/libc.so.6:0000000000038c40 t __internal_atexit
/usr/lib64/libc.so.6:00000000003b6838 d __start___libc_atexit
/usr/lib64/libc.so.6:00000000003b6840 d __stop___libc_atexit
nm: /lib64/libc.so: File format not recognized
/lib64/libc.so.6:00000000003bcc00 b added_atexit_handler.9157
/lib64/libc.so.6:0000000000038c90 T __cxa_atexit
/lib64/libc.so.6:0000000000038c90 t __cxa_atexit_internal
/lib64/libc.so.6:00000000003b6838 d __elf_set___libc_atexit_element__IO_cleanup__
/lib64/libc.so.6:0000000000038c40 t __internal_atexit
nm: /usr/lib64/libc.so: File format not recognized
/lib64/libc.so.6:00000000003b6838 d __start___libc_atexit
/lib64/libc.so.6:00000000003b6840 d __stop___libc_atexit
/usr/lib64/libc.so.6:00000000003bcc00 b added_atexit_handler.9157
/usr/lib64/libc.so.6:0000000000038c90 T __cxa_atexit
/usr/lib64/libc.so.6:0000000000038c90 t __cxa_atexit_internal
/usr/lib64/libc.so.6:00000000003b6838 d __elf_set___libc_atexit_element__IO_cleanup__
/usr/lib64/libc.so.6:0000000000038c40 t __internal_atexit
/usr/lib64/libc.so.6:00000000003b6838 d __start___libc_atexit
/usr/lib64/libc.so.6:00000000003b6840 d __stop___libc_atexit
$
There's no evidence of a plain atexit function there. Where's it hiding, and what's with those 'File format not recognized' messages?
$ file /usr/lib64/libc.so
/usr/lib64/libc.so: ASCII text
$
ASCII text? What?
$ cat /usr/lib64/libc.so
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )
$
OK; what's in /usr/lib64/libc_nonshared.a?
$ nm /usr/lib64/libc_nonshared.a | grep -i atexit
atexit.oS:
0000000000000000 T atexit
U __cxa_atexit
$
Bingo! Found it!
So, it seems that the collect2 linker used by GCC is able to load files not listed on the command line, and that one of those files is /usr/lib64/libc_nonshared.a, and that this library has atexit() in it. Consequently, you should be able to invoke atexit() because it is statically linked into the executable … unless there's some more black magic hidden away here that I've not sussed out.
For some reason I am getting this
error message and won't allow me to step through my code.
ubuntu (master *) ECS150-Simple-Shell $ gdb sshell
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from sshell...(no debugging symbols found)...done.
(gdb) b LoadTerminal
Breakpoint 1 at 0x4010e8
(gdb) r
Starting program: /media/ubuntu/folder/sshell
warning: the debug information found in "/lib64/ld-2.23.so" does not match "/lib64/ld-linux-x86-64.so.2" (CRC mismatch).
Breakpoint 1, 0x00000000004010e8 in LoadTerminal ()
(gdb) n
Single stepping until exit from function LoadTerminal,
which has no line number information.
sshell$
Instead of stepping through line by line, it stepped through the end of the code.
My Makefile
objects = main.o terminal.o history.o parser.o
cc = gcc
cflags = -g -Werror
sshell: $(objects)
$(cc) $(cflags) $(objects) -o sshell
rm $(objects)
main.o: main.c
terminal.o: terminal.c
history.o: history.c
parser.o: parser.c
.PHONY: clean
clean:
rm sshell
My Makefile with -g on every object file
objects = main.o terminal.o history.o parser.o
cc = gcc
cflags = -g -Werror
sshell: $(objects)
$(cc) $(cflags) $(objects) -o sshell
rm $(objects)
main.o: main.c
gcc -g -Werror -c main.c -o main.o
terminal.o: terminal.c
gcc -g -Werror -c terminal.c -o terminal.o
history.o: history.c
gcc -g -Werror -c history.c -o history.o
parser.o: parser.c
gcc -g -Werror -c parser.c -o parser.o
.PHONY: clean
clean:
rm sshell
I have even tried adding the -g options to my object files, but I get the same error.
For some reason
There are a few possible reasons. The most likely reason that I could guess is that your gcc isn't really a /usr/bin/gcc, but some shell wrapper, which passes different flags to /usr/bin/gcc.
Another possible reason is that you are debugging the wrong binary. GDB says you are debugging /media/ubuntu/folder/sshell, but is that the binary that you build?
My Makefile.
There doesn't seem to be anything wrong with your Makefile (besides using unconventional variables for CC, CLFAGS, etc. -- make is case-sensitive).
Instead of showing the Makefile, you really should snow the command that make clean sshell produces.
Here are the steps I would use to triage this problem:
Verify that the compile and final link commands actually contain -g
Verify that gcc is /usr/bin/gcc
Verify that /media/ubuntu/folder/sshell has been modified at expected time (with ls -l).
Verify that it contains debug info: readelf -WS /media/ubuntu/folder/sshell | grep '\.debug'
At least one of the above statements likely false. If they are all true, you have a broken GCC or binutils installation.
I am trying to compile a large C file (specifically for MATLAB mexing). The C file is around 20 MB (available from the GCC bug tracker if you want to play around with it).
Here is the command I am running and the output to screen, below. This has been running for hours, and as you can see, optimization is already disabled (-O0). Why is this so slow? Is there a way I can make this faster?
(For reference: Ubuntu 12.04 (Precise Pangolin) 64 bit and GCC 4.7.3)
/usr/bin/gcc -c -DMX_COMPAT_32 -D_GNU_SOURCE -DMATLAB_MEX_FILE -I"/usr/local/MATLAB/R2015a/extern/include" -I"/usr/local/MATLAB/R2015a/simulink/include" -ansi -fexceptions -fPIC -fno-omit-frame-pointer -pthread -O0 -DNDEBUG path/to/test4.c -o /tmp/mex_198714460457975_3922/test4.o -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.3-2ubuntu1~12.04' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04)
COLLECT_GCC_OPTIONS='-c' '-D' 'MX_COMPAT_32' '-D' '_GNU_SOURCE' '-D' 'MATLAB_MEX_FILE' '-I' '/usr/local/MATLAB/R2015a/extern/include' '-I' '/usr/local/MATLAB/R2015a/simulink/include' '-ansi' '-fexceptions' '-fPIC' '-fno-omit-frame-pointer' '-pthread' '-O0' '-D' 'NDEBUG' '-o' '/tmp/mex_198714460457975_3922/test4.o' '-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -I /usr/local/MATLAB/R2015a/extern/include -I /usr/local/MATLAB/R2015a/simulink/include -imultilib . -imultiarch x86_64-linux-gnu -D_REENTRANT -D MX_COMPAT_32 -D _GNU_SOURCE -D MATLAB_MEX_FILE -D NDEBUG path/to/test4.c -quiet -dumpbase test4.c -mtune=generic -march=x86-64 -auxbase-strip /tmp/mex_198714460457975_3922/test4.o -O0 -ansi -version -fexceptions -fPIC -fno-omit-frame-pointer -fstack-protector -o /tmp/ccxDOA5f.s
GNU C (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) version 4.7.3 (x86_64-linux-gnu)
compiled by GNU C version 4.7.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/MATLAB/R2015a/extern/include
/usr/local/MATLAB/R2015a/simulink/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) version 4.7.3 (x86_64-linux-gnu)
compiled by GNU C version 4.7.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: c119948b394d79ea05b6b3986ab084cf
EDIT: a follow-on: I followed chqrlie's advice and tcc compiled my function in <5 seconds (I had to remove the -ansi flag only and turn "gcc" to "tcc"), which is pretty remarkable, really. I can only imagine the complexity of GCC.
When trying to then mex it, however, there is one other command mex typically needs. The second command is typically:
/usr/bin/gcc -pthread -Wl,--no-undefined -Wl,-rpath-link,/usr/local/MATLAB/R2015a/bin/glnxa64 -shared -O -Wl,--version-script,"/usr/local/MATLAB/R2015a/extern/lib/glnxa64/mexFunction.map" /tmp/mex_61853296369424_4031/test4.o -L"/usr/local/MATLAB/R2015a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -o test4.mexa64
I cannot run this with tcc as some of these flags are not compatible. If I try to run this second compilation step with GCC, I get:
/usr/bin/ld: test4.o: relocation R_X86_64_PC32 against undefined symbol `mxGetPr' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
EDIT: The solution appears to be clang. tcc can compile the file, but the arguments in the second step in mexing are incompatible with tcc's argument options. Clang is very fast and produces a nice, small, optimized file.
Nearly the entire file is one expression, the assignment to double f[24] = .... That's going to generate a gigantic abstract syntax tree tree. I'd be surprised if anything but a specialized compiler could handle that efficiently.
The 20 megabyte file itself may be fine, but the one giant expression may be what is causing the issue. Try as a preliminary step, splitting the line into double f[24] = {0} and then 24 assignments of f[0] = ...; f[1] = ... and see what happens. Worst case, you can split the 24 assignments into 24 functions, each in its own .c file, and compile them separately. This won't reduce the size of the AST, it will just reorganize it, but GCC is probably more optimized at handling many statements which together add up to a lot of code, vs. one huge expression.
The ultimate approach would be to generate the code in a more optimized manner. If I search for s4*s5*s6, for example, I get 77,783 hits. These s[4-6] variables don't change. You should generate a temporary variable, double _tmp1 = s4*s5*s6; and then use that instead of repeating the expression. You've just eliminated 311,132 nodes from your abstract syntax tree (assuming s4*s5*s6 is 5 nodes and _tmp1 is one node). That's that much less processing GCC has to do. This should also generate faster code (you won't repeat the same multiplication 77,783 times).
If you do this in a smart way in a recursive manner (e.g. s4*s5*s6 --> _tmp1, (c4*c6+s4*s5*s6) --> (c4*c6+_tmp1) --> _tmp2, c5*s6*(c4*c6+s4*s5*s6) --> c5*s6*_tmp2 -> _tmp3, etc...), you can probably eliminate most of the size of the generated code.
Upon testing, I found that the Clang compiler seems to have less problems compiling large files. Although Clang consumed almost a gigabyte of memory during compilation, it successfully turned OP's source code form into a 70 kB object file. This works for all optimization levels I tested.
gcc was also able to compile this file quickly and without consuming too much memory if optimization is turned on. This bug in gcc comes from the large expression in OPs code which places a huge burden on the register allocator. With optimizations turned on, the compiler performs an optimization called common subexpression elimination which is able to remove a lot of redundancy from OPs code, reducing both compilation time and object file size to manageable values.
Here are some tests with the testcase from the aforementioned bug report:
$ time gcc5 -O3 -c -o testcase.gcc5-O3.o testcase.c
real 0m39,30s
user 0m37,85s
sys 0m1,42s
$ time gcc5 -O0 -c -o testcase.gcc5-O0.o testcase.c
real 23m33,34s
user 23m27,07s
sys 0m5,92s
$ time tcc -c -o testcase.tcc.o testcase.c
real 0m2,60s
user 0m2,42s
sys 0m0,17s
$ time clang -O3 -c -o testcase.clang-O3.o testcase.c
real 0m13,71s
user 0m12,55s
sys 0m1,16s
$ time clang -O0 -c -o testcase.clang-O0.o testcase.c
real 0m17,63s
user 0m16,14s
sys 0m1,49s
$ time clang -Os -c -o testcase.clang-Os.o testcase.c
real 0m14,88s
user 0m13,73s
sys 0m1,11s
$ time clang -Oz -c -o testcase.clang-Oz.o testcase.c
real 0m13,56s
user 0m12,45s
sys 0m1,09
This is the resulting object file size:
text data bss dec hex filename
39101286 0 0 39101286 254a366 testcase.clang-O0.o
72161 0 0 72161 119e1 testcase.clang-O3.o
72087 0 0 72087 11997 testcase.clang-Os.o
72087 0 0 72087 11997 testcase.clang-Oz.o
38683240 0 0 38683240 24e4268 testcase.gcc5-O0.o
87500 0 0 87500 155cc testcase.gcc5-O3.o
78239 0 0 78239 1319f testcase.gcc5-Os.o
69210504 3170616 0 72381120 45072c0 testcase.tcc.o
Try Fabrice Bellard's tiny C compiler tcc from http://tinycc.org:
chqrlie$ time tcc -c test4.c
real 0m1.336s
user 0m1.248s
sys 0m0.084s
chqrlie$ size test4.o
text data bss dec hex filename
38953877 3170632 0 42124509 282c4dd test4.o
Yes, that's 1.336 seconds on a pretty basic PC!
Of course I cannot test the resulting executable, but the object file should be linkable with the rest of your program and libraries.
For this test, I used a dummy version of file mex.h:
typedef struct mxArray mxArray;
double *mxGetPr(const mxArray*);
enum { mxREAL = 0 };
mxArray *mxCreateDoubleMatrix(int nx, int ny, int type);
gcc still has not finished compiling...
EDIT: gcc managed to hog my Linux box so badly I cannot connect to it anymore:(