I tried to run an example program from a book called 'The Linux Programming Interface'. I copied all user-defined header files and functions from official website of book to my booklib location.
When I compiled the program, I took these errors. I need help about'Undefined reference to [functions_name]**.
code:
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include "tlpi_hdr.h"
#ifndef BUF_SIZE
#define BUF_SIZE 1024
#endif
int main(int argc, char *argv[])
{
int inputFd, outputFd, openFlags;
mode_t filePerms;
ssize_t numRead;
char buf[BUF_SIZE];
if(argc != 3 || strcmp(argv[1], "--help") == 0)
{
usageErr("%s old-file new-file\n", argv[0]);
}
//open input old-file
inputFd = open(argv[1], O_RDONLY);
//error check
if(inputFd == -1)
{
errExit("opening file %s", argv[1]);
}
openFlags = O_CREAT | O_WRONLY | O_TRUNC;
filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
//open output the new-file
outputFd = open(argv[2], openFlags, filePerms);
if(outputFd == -1)
{
errExit("opening file %s", argv[2]);
}
//transfer data until we encounter end of input or an error
while((numRead = read(inputFd, buf, BUF_SIZE)) > 0)
{
if(write(outputFd, buf, numRead) != numRead)
fatal("couldn't write whole buffer");
if(numRead == -1)
errExit("read");
if(close(inputFd) == -1)
errExit("close input");
if(close(outputFd) == -1)
errExit("close output");
}
exit(EXIT_SUCCESS);
}
You can see user-defined header files from here.
$gcc -I booklib -o copy copy.c
c
/tmp/ccqC9Tg9.o: In function `main':
copy.c:(.text+0x62): undefined reference to `usageErr'
copy.c:(.text+0xb3): undefined reference to `errExit'
copy.c:(.text+0x11c): undefined reference to `errExit'
copy.c:(.text+0x14b): undefined reference to `fatal'
copy.c:(.text+0x163): undefined reference to `errExit'
copy.c:(.text+0x183): undefined reference to `errExit'
copy.c:(.text+0x1a3): undefined reference to `errExit'
collect2: error: ld returned 1 exit status
gcc -v output:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-6' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --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 6.3.0 20170205 (Debian 6.3.0-6)
For the undefined references, someone asked a very similar answer here How to compile examples in the book "The Linux Programming Interface" by Michael Kerrisk
Then, if that does not work, I would suggest to try again by downloading the source file as specified at the TLPI web site and you can look into the makefile for your script, which is in the fileio/ subfolder and the Makefile.inc file.
I was having the exact same issues with undefined references to his error-handling functions, but if you're doing everything in your own directories my advice may not help. If you downloaded the compressed tarball from his website everything should work. As stated in the BUILDING.txt file it includes, all you have to do is run make from the tlpi-dist or tlpi-book directory, depending on which one you downloaded, and all programs will be compiled and ready to run (subject to some OS specific issues obviously). If you want to modify a program, just add the name you save it as to that directory's Makefile and run make again, and you should be good to go.
I was having similar troubles on Ubuntu 16.04. and MacOSX.
Running 'make' always gave errors containing:
No rule to make target `../libtlpi.a'
This has a simple solution for Ubuntu:
sudo apt-get install libcap-dev
then run 'make' in the root directory.
You would require to ../lib/error_functions.o file along with your compilation.
gcc -I booklib -o copy copy.c ../lib/error_functions.o
The error functions are defined and declared in lib/error_functions.c lib/error_function.h
Make sure you run make from tlpi-dist by which you would have error_functions.o
Related
This question already has answers here:
literal constant vs variable in math library
(4 answers)
Do math functions of constant expressions get pre-calculated at compile time?
(6 answers)
Closed 4 years ago.
Using gcc test.c, the first code sample compiles, while the second does not. Why?
They both work with explicit linking of the math library (i.e. gcc test.c -lm.
First Sample:
#include <stdio.h>
#include <math.h>
int main () {
printf("%lf\n", sqrt(4.0) );
return 0;
}
Second Sample:
#include <math.h>
#include <stdio.h>
double sqrt2(double a) { return sqrt(a); }
int main() {
printf("%lf\n", sqrt(4.0));
printf("%lf\n", sqrt2(4.0));
return 0;
}
Linker error with second sample:
/tmp/ccuYdso7.o: In function `sqrt2':
test.c:(.text+0x13): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
gcc -v:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-mul
Thread model: posix
gcc version 8.1.0 (GCC)
There is no linker error for uses of sqrt in the main function. Is there any particular reason that this is the case?
I also checked with clang, but neither compiled (linker errors) without the -lm.
gcc is a particularly clever compiler.
It will optimise out sqrt(4.0) as a compile time evaluable constant expression. It can do that since the definition of sqrt is defined by the standard and its return value is solely a function of its input. (Note futher that under IEEE754, sqrt must return the closest double to the final result. This further supports the optimisation hypothesis.)
In the second case, the presence of function (which could be used by other translation units) defeats this optimisation.
Since the argument to sqrt is known at compile time, and its behaviour is standardised, sqrt(4.0) can be calculated at compile time.
I have a compilation problem with gcc.
Assume the following program:
#include <stdio.h>
int test(const char *fname) {
FILE *fh = fopen(fname, "rb");
int tmp;
if (fread(&tmp, sizeof(tmp), 1, fh) < 1) {
tmp = 0;
}
fclose(fh);
return tmp;
}
int main(void) {
printf("%d\n", test("test.txt"));
return 0;
}
And the file test.txt:
11111111111111111111111111111111...
Of course, the program is very stupid, but it works:
user#ubuntu:~/tmp/optxx$ gcc -O3 -Wall -Wextra test.c
user#ubuntu:~/tmp/optxx$ ./a.out
825307441
Let's modify it a bit (only add an attribute to the test-function):
#include <stdio.h>
int __attribute__((optimize("O0"))) test(const char *fname) {
FILE *fh = fopen(fname, "rb");
int tmp;
if (fread(&tmp, sizeof(tmp), 1, fh) < 1) {
tmp = 0;
}
fclose(fh);
return tmp;
}
int main(void) {
printf("%d\n", test("test.txt"));
return 0;
}
The function test should no longer be optimized. But now compilation fails:
user#ubuntu:~/tmp/optxx$ gcc -Wall -Wextra -O3 test.c
In file included from /usr/include/stdio.h:936:0,
from test.c:1:
In function ‘fread’,
inlined from ‘test’ at test.c:6:9:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:293:9: warning: call to ‘__fread_chk_warn’ declared with attribute warning: fread called with bigger size * nmemb than length of destination buffer
return __fread_chk_warn (__ptr, __bos0 (__ptr), __size, __n, __stream);
^
I get a warning and normally i compile with -Werror, so i don't like warnings.
The used gcc version:
user#ubuntu:~/tmp/optxx$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.3.1-6ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --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 5.3.1 20160119 (Ubuntu 5.3.1-6ubuntu2)
Unfortunately i am not able to fix the warning:(
Maybe someone has an idea why this happens?
-edit-
A (dirty) hack would also be okay to remove this warning:)
-edit-
Probably something with my linux is wrong, because it seems to work for everyone else. Anayway a dirty hack / fix would be to add this code before the fread call:
static size_t fread_wrapper(void *ptr, size_t size, size_t count, FILE *stream) {
return fread(ptr, size, count, stream);
}
#define fread(ptr, size, count, stream) fread_wrapper((ptr), (size), (count), (stream))
Ubuntu enable the _FORTIFY_SOURCE feature by default for optimization levels -O1 or higher. This option makes the system headers pre-process to use different functions for fread among others. Those functions perform some basic safety checks of arguments. The option gets enabled globally when the header is included so it makes the assumption that all the code will be compiled with -O1 or higher. I assume that it is disabled on lower optimization levels because gcc doesn't have enough information without some optimizations and that causes those magic fortify macros to generate false positives (like you got).
If you compile the whole file with -O0, _FORTIFY_SOURCE is disabled and things will work. Alternatively I guess you can compile the whole file with -D_FORTIFY_SOURCE=0, although I haven't tried it.
Also, I could reproduce this on other flavors of linux by just adding -D_FORTIFY_SOURCE=1.
I guess you can call it a compiler/glibc/Ubuntu bug. Or just stop using crazy optimization attributes. The world can't be tested with all possible weird combinations so we should exercise caution when pushing buttons and turning knobs.
For a homework assignment, I have to try to use buffer overflows to crash a simple c program. My problem is that my compiler won't compile the gets() function because it is deprecated and unsafe. I understand this, but for the sake of the example, I'd like to override that. Here is the code:
#include <stdio.h>
int main(int argc, char *argv[]) {
int valid = 0;
// Char arrays w/buffer set to 8 chars
char str1[8];
char str2[8];
next_tag(str1);
//This is where I want to use gets and not fgets or other secure functions...
gets(str2);
if(strncmp(str1, str2, 8) == 0) {
valid = 1;
}
// Print
printf("Buffer 1: str1(%s), str2(%s), valid(%d)\n", str1, str2, valid);
}
My gcc version is:
rabbitfighter#ECHO:[~/Code/C/BufferOverflowExamples]: gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.9.1/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /build/gcc/src/gcc-4.9-20140903/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-cloog-backend=isl --disable-isl-version-check --disable-cloog-version-check --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --disable-multilib --disable-werror --enable-checking=release
Thread model: posix
gcc version 4.9.1 20140903 (prerelease) (GCC)
If anyone can help me I would greatly appreciate it. I am running Manjaro Linux (Arch).
You can use a "safer" funcion like fgets and give it a bogus buffer size to get unsafe behavior out of it.
A larger buffer size than the real buffer will let fgets overrun its bounds and potentially crash the program.
Just because the gun has a safety doesn't mean you can't shoot your foot off with it.
I executed the below C program which prints a the primes below the given N (N < 4294967295). It went fine when executed in SunOS, but I'm getting Segmentation fault (core dumped) when running in Ubuntu(compiled it with gcc compilter). Can anyone please let me know where I went wrong. Mentioned below the compiler versions of SunOS and Ubuntu 12.10
cc -V
cc: Sun C 5.9 SunOS_sparc Patch 124867-01 2007/07/12
gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.2-2ubuntu1' --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 --with-system-zlib --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 --enable-objc-gc --disable-werror --with-arch-32=i686 --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.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<inttypes.h>
int main()
{
FILE *fpin,*fpout;
char ch[11], file_name[100];
long long int num1=0,i,tmp=0;
long long int *arr;
printf("enter file name:: ");
gets(file_name);
fpin = fopen(file_name,"r");
fpout = fopen("/home/code/output.c","w");
while(1)
{
fgets(ch,11,fpin);
if (!feof(fpin))
{
num1=atoll(ch);
arr = prime_number(num1);
for(i=0;*(arr+i)!='\0';i++)
{
fprintf(fpout,"%llu",*(arr+i));
if(*(arr+i+1) == '\0')
fputc('.',fpout);
else
fputc(',',fpout);
}
}
else
{
fclose(fpin);
fclose(fpout);
break;
}
}
}
prime_number(long long int n)
{
long long int i,j,total=0,a[200];
int count=0;
printf("\n%llu \n",n);
for (j=2;j<=n;j++)
{
count = 0;
for (i=1;i<=j;i++)
{`enter code here`
if ((j%i) == 0)
count++;
if (count > 2)
break;
}
if (count==2)
{
a[total] = j;
total++;
}
}
return(&a[0]);
}
At the end of your prime_number funciton, you are returning a pointer to a variable which is defined in (the stack of) the prime_number function itself. Since when the function exists, the contents of its stack are effectivley vaporized, you are returning an invalid pointer.
Of course, depending on what system, OS, etc you are running, the contents of the stack may have not been immediatley overwritten and would APPEAR valid for a short period of time, but this is just luck.
Try either mallocing a return result (and freeing with your caller), or passing the array TO the prime_number function. This way, the contents will remain valid for the caller.
return(&a[0]);
You're returning a pointer to a local variable, which doesn't exist after your function returns.
If you run gcc with warnings, your compiler should tell you this.
How do I use the GNU C Library version of basename() and dirname()?.
If you
#include <libgen.h>
for dirname
You're already getting the POSIX, not the GNU, version of basename(). (Even if you
#define _GNU_SOURCE
As far as I know there is no conditional importing in C. Is there a gcc specific trick?
Just write it yourself and give it a different name than basename. This GNU insistence on creating alternate non-conforming versions of standard functions that can be written in 1-3 lines is completely batty.
char *gnu_basename(char *path)
{
char *base = strrchr(path, '/');
return base ? base+1 : path;
}
This way, your program will also be more portable.
According to the man page you should do
#define _GNU_SOURCE
#include <string.h>
If you get the POSIX version, libgen.h is probably already included before that point. You may want to include -D_GNU_SOURCE in the CPPFLAGS for compilation:
gcc -D_GNU_SOURCE ....
Compare: POSIX Version vs GNU Version on Compiler Explorer.
After examining libgen.h, I'm pretty sure I have a warning-free and error-free solution:
/* my C program */
#define _GNU_SOURCE /* for GNU version of basename(3) */
#include <libgen.h> /* for dirname(3) */
#undef basename /* (snide comment about libgen.h removed) */
#include <string.h> /* for basename(3) (GNU version) and strcmp(3) */
/* rest of C program... */
With the #undef line, now my program includes dirname(3) from libgen.h and the GNU version of basename(3) from string.h.
No compiler warnings/errors from either gcc (version 4.5.2) or clang (version 3.3).
Make sure you're building with the GNU C library, rather than your system's (presumed) POSIX-compatible default.
This is often set in the GCC spec file. Use the -v option to show the current settings:
$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.4.4-14ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i686 --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.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
It's crazy basename and dirname have two versions.
We worked at a big project, it looks like these two apis already caused
potentially bugs. So we marked "basename" "dirname" as deprecated for warning if
someone use it:
#ifdef basename
__attribute__ ((deprecated))
char *__xpg_basename(char *path);
#else
__attribute__ ((deprecated))
char *basename(const char *path);
#endif
__attribute__ ((deprecated))
char *dirname(char *path);
We also try to introduce a base c foundation library such as glib or libcork,
but it looks like too heavy. So we write a tiny library for this purpose, it
implementation like this:
#include <libgen.h> // for dirname
#include <linux/limits.h> // for PATH_MAX
#include <stdio.h> // for snprintf
#include <string.h> // for basename
#include <stdbool.h> // for bool
bool get_basename(const char *path, char *name, size_t name_size) {
char path_copy[PATH_MAX] = {'\0'};
strncpy(path_copy, path, sizeof(path_copy) - 1);
return snprintf(name, name_size, "%s", basename(path_copy)) < name_size;
}
bool get_dirname(const char *path, char *name, size_t name_size) {
char path_copy[PATH_MAX] = {'\0'};
strncpy(path_copy, path, sizeof(path_copy) - 1);
return snprintf(name, name_size, "%s", dirname(path_copy)) < name_size;
}
Then we replace all basename dirname call with get_basename get_dirname.