Multiple definitions when making kernel module over multiple source files - c

I think the problem is having one header file that has all items that my source files needs, but how do I fix this? Is it possible to use one or must I split them up with their own includes functionalities.
I not sure what wrong with my .h file that I'm including in all my source files. I read that the problem is each source file is compiling separately with this .h file and when linking all source files together, the compile finds there are multiple definitions even though I have a include guard.
How can I go about this? There's prototype.h that includes all my function prototypes, includes, extern variables, and structs. I have a few source files that all need some portion of this .h file.
My make file is as follows
TARGET = betty
obj-m := $(TARGET).o
betty-objs := main.o helpers.o syscall_overrides.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(RM) .*.cmd *.o *.ko -r .tmp*
And the error message (a portion of them) that it gives is:
/home/admin/Dropbox/COMP3000/FinalModule/helpers.o:(.bss+0x4): multiple definition of `clean_sys_mkdir'
/home/admin/Dropbox/COMP3000/FinalModule/main.o:(.bss+0x0): first defined here
/home/admin/Dropbox/COMP3000/FinalModule/helpers.o:(.bss+0x8): multiple definition of `clean_sys_execve'
/home/admin/Dropbox/COMP3000/FinalModule/main.o:(.bss+0x4): first defined here
/home/admin/Dropbox/COMP3000/FinalModule/helpers.o:(.bss+0xc): multiple definition of `clean_getdents64_syscall'
Code:
main.c
#define MODULE_NAME "Betty"
#include "prototypes.h"
extern unsigned long **syscall_table;
static int __init init(void)
{
...
}
static void __exit shutdown(void)
{
...
}
module_init(init);
module_exit(shutdown);
MODULE_LICENSE("..");
MODULE_AUTHOR("..");
MODULE_DESCRIPTION("..");
prototype.h
#ifndef PROTOTYPE_H
#define PROTOTYPE_H
#include <linux/module.h> // mandatory kernel module
#include <linux/kernel.h> // KERN_INFO
#include <linux/init.h> // __init and __exit
#include <asm/unistd.h> // __NR syscall nums
#include <linux/printk.h>
#include <linux/tty.h> // tty_struct
#include <linux/tty_driver.h>// write (already included by tty.h)
#include <linux/sched.h> // current
#include <linux/random.h> // get_random_bytes
#include <linux/syscalls.h> // from sys_execve asmlinkage
#include <linux/dirent.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/slab.h> // kmalloc()
#include <linux/time.h> // time
#include <linux/rtc.h> // rtc_time_to_tm
/*
Function prototypes for both original and custom syscalls that Betty uses
*/
asmlinkage long (*clean_sys_mkdir)(const char __user *pathname, umode_t mode);
asmlinkage long (*clean_sys_execve)(const char __user *filename,
const char __user *const __user *argv,
const char __user *const __user *envp);
asmlinkage long (*clean_getdents64_syscall) (unsigned int fd,
struct linux_dirent64 __user * dirent,
unsigned int count);
static void find_process_id_to_hide(char* process_nm);
extern unsigned long **syscall_table;
#endif
helpers.c
#include "prototypes.h"
extern unsigned long **syscall_table; // extern variable
... just functions in this one defined in prototype.h

Related

Why one head file can use other head files directly without include them

It is on VS Code
first I have type.h
typedef unsigned int uint;
typedef unsigned long long uint64;
then I have defs.h
uint fun1(uint);
uint64 fun2(uint64);
then is the main.c
#include <stdio.h>
#include "types.h"
#include "defs.h"
uint fun1(uint x) {
return x;
}
uint64 fun2(uint64 x) {
return x;
}
int main() {
printf("%d, %llu\n", fun1(10), fun2(20));
return 0;
}
I mean why can I use uint and uint64 in defs.h that are defined in types.h without including it, and the IntelliSense plug doesn't give me warnings
Header files are not processed in isolation. In main.c, you have:
#include <stdio.h>
#include "types.h"
#include "defs.h"
…
When the compiler is asked to compile main.c, it reads the line #include <stdio.h>. That line tells the compiler to read <stdio.h> and process the contents of <stdio.h> as if they were in main.c. That continues with each #include directive; the contents of the included file become part of the source code being compiled.
Thus, the result of those three directives is as if main.c contained, in part:
…
typedef unsigned int uint;
typedef unsigned long long uint64;
uint fun1(uint);
uint64 fun2(uint64);
…
So when the compiler is processing uint fun1(uint); from "defs.h", it has already seen typedef unsigned int uint from "types.h".
If you instructed the compiler to compile defs.h as C source code alone, or to compile a source file that included defs.h but did not include types.h, then the compiler would not have the definitions of uint and uint64 and would complain about their use.
It is generally good practice for each header file to have a #include directive for each header file that provides definitions or declarations that the file needs, so your defs.h should have a line #include "types.h". (There may be exceptions to this.)

Using char in different files in C

I have 3 .c files main.c, fun1.c, fun2.c
char buff[50];//in fun1.c
char *arg; //in fun2.c
arg = strstr(buff, "001"); //in fun2.c
I want to print buff in fun2.c but it gives an error buff undeclared, even though I declared it in fun1.h as extern char buff[];
There are functions in fun1.c and fun2.c each
It is hard to say what is wrong with your particular program, but here is an example which links 2 .c files with one .h file.
1. A header file functions.h:
#include <stdio.h>
extern void func();
Where I use extern to provide definitions for another file.
2. Now, a functions.c file which uses this header file:
#include "functions.h"
void func() {
printf("hello");
}
This needs to #include the header file, and use the function void() to print a message.
3. Finally, a main.c file which links it all together:
#include <stdio.h>
#include <stdlib.h>
#include "functions.h"
int main(void) {
func();
return 0;
}
Which also needs function.h as it uses func(). You then can compile the code as:
gcc -Wall -Wextra -g main.c functions.c -o main
You could also look into makefiles, which would reduce this long compilation line to simply make.

Error unkown filetype although it is declared in a header file and included

i have an error that I do not understand. I can get rid of the error if I just put the include in the mail.c file and not in the mail.h file. My code looks like this:
The mail.h file:
#ifndef MAIL_H
#define MAIL_H
//Normal needed headers
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//Custom headers
#include "pop3.h"
#include "pasw.h"
#include "rese.h"
#define NAME_SIZE 100 //Defines the length of e.g. the user name
#define PASSW_SIZE 100 //Defines the length of the password
#define ADD_SPACE 10 //Defines some additional space for arrays
#define HELPTEXT "help.txt" //Defines the name of the help.txt file
enum bool {true, false};
typedef enum bool bool;
#endif
The pop3.h file:
#ifndef POP3
#define POP3
// Open SSl headers
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//Needed for the password input to not show the password
#include <termios.h>
//Normal needed headers
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//Custom headers
#include "mail.h"
#include "pasw.h"
#include "rese.h"
void pop3(unsigned char *, unsigned char *, unsigned char *);
int GetUserPassw(unsigned char *, unsigned char *);
int login(BIO *, unsigned char *, unsigned char *, unsigned char *, bool, bool);
int GetUsername(unsigned char *;);
int GetInput(unsigned char*, int);
int GetNumberOfMessages(BIO *);
void RetrieveEmail(BIO *);
#endif
In mail. c I have included mail.h and in pop3.c I have included pop3.h. The error I get is:
gcc -lcrypto -lssl -c mail.c
In file included from mail.h:10:0,
from mail.c:11:
pop3.h:24:69: error: unknown type name ‘bool’
int login(BIO *, unsigned char *, unsigned char *, unsigned char *, bool, bool);
^
pop3.h:24:75: error: unknown type name ‘bool’
int login(BIO *, unsigned char *, unsigned char *, unsigned char *, bool, bool);
^
Makefile:12: recipe for target 'mail.o' failed
make: *** [mail.o] Error 1
And my Makefile looks like this:
CC=gcc
CFLAGS=-lcrypto -lssl -o
OFLAGS=-lcrypto -lssl -c
RM=rm -i
all: mail
mail: mail.o pop3.o pasw.o rese.o
$(CC) $(CFLAGS) mail mail.o pop3.o pasw.o rese.o
mail.o: mail.c
$(CC) $(OFLAGS) mail.c
pop3.o: pop3.c
$(CC) $(OFLAGS) pop3.c
pasw.o: pasw.c
$(CC) $(OFLAGS) pasw.c
rese.o: rese.c
$(CC) $(OFLAGS) rese.c
clean:
rm *.o mail
Before I have changed the file structure a bit it has worked. But I can get rid of this problem by puting the include "commands" out of mail.h and into mail.c.
I am looking forward to hear from you.
King regards,
Greenality
First of all read my comment. Second of all, you define the type bool after you include the headers that depend on the type.
In pop3.h you use the type bool in the function declaration of
int login(BIO *, unsigned char *, unsigned char *, unsigned char *, bool, bool);
But when pop3.h is included into mail.h, bool is not defined at that point yet where pop3.h is included.
As you also include mail.h into pop3.h, you have a cyclic dependency between the header files, so you'd have to create its own file for the type bool and #include it into the pop3.h header. An alternative is to clean up your header dependencies properly as pop3.h has only a dependency on #include <openssl/bio.h> and the bool type.
Also instead of creating your own boolean type, use the bool from stdbool.h which is also properly convertible unlike yours and uses a real boolean type if the compiler provides it.
So your pop3.h would end up as
#ifndef POP3
#define POP3
#include <stdbool.h>
// Open SSl headers
#include <openssl/bio.h>
void pop3(unsigned char *, unsigned char *, unsigned char *);
int GetUserPassw(unsigned char *, unsigned char *);
int login(BIO *, unsigned char *, unsigned char *, unsigned char *, bool, bool);
int GetUsername(unsigned char *;);
int GetInput(unsigned char*, int);
int GetNumberOfMessages(BIO *);
void RetrieveEmail(BIO *);
#endif
while the missing header files required for the implementation will be directly included into the pop3.c file:
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "mail.h"
#include "pasw.h"
#include "rese.h"
I can't help you with mail.h as it's missing its interface. Everything that you have in your mail.h should actually be in mail.c as it's about implementation details.
Only what you want to provide to users of your mail.c implementation should be part of the interface in mail.h.
When compiling mail.c, the file first includes the content of mail.h, which in turn includes the content of pop.h, which attempts to include mail.h but ends up getting nothing from the file due to MAIL_H being already defined.
Since pop.h was included before enum bool was defined in mail.h, the content of pop.h has no knowledge of what bool is. Therefore the compiler error. Simply define enum bool before including pop.h in mail.h should solve the problem.

gcc compile time type resolution

I have three files, say A.c , B.c and C.c, all of which #include common.h
In common.h, I include "sys/socket.h" and I protect the common.h by macros:
#ifndef __COMMON_H
#define __COMMON_H
// body of file goes here
#endif
When i compile the code, I get several errors such as below
In file included from /usr/include/sys/socket.h:40,
from tcpperf.h:4,
from wrapunix.c:1:
/usr/include/bits/socket.h:425: error: conflicting types for 'recvmmsg'
/usr/include/bits/socket.h:425: note: previous declaration of 'recvmmsg' was here
In file included from /usr/include/sys/socket.h:40,
from tcpperf.h:4,
from wrapsock.c:1:
As you can see wrapunix.c and wrapsock.c, they both include tcpperf.h, but tcpperf.h is guarded with macros,yet gcc complains that recvmsg was declared multiple times. How do I resolve this issue?
Update:
Here is the header of tcpperf.h, that is causing issues
#ifndef _TCPPERF_H
#define _TCPPERF_H
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <regex.h>
#include <errno.h>
#include <sched.h>
#include <pthread.h>
#include <argp.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <linux/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/wait.h>
#endif
The above error can be reproduced by providing "-combine -fwhole-program" flags to gcc such as
gcc -std=gnu99 -Wall -combine -fwhole-program -I. error.c wrapunix.c wrapsock.c file1.c file2.c -o file2 -lrt
The error is "conflicting types for 'recvmmsg'" rather than just duplicate definition (which would be tolerated if equal). That means your .c source receives two different version of recvmmsg: one by your direct tcpperf.h inclusion and another one by inclusion it via sys/socket.h. I believe you have another version of tcpperf.h elsewhere in inclusion path with different (perhaps older version) recvmmsg.
The problem is almost certainly related to -combine. This is a bit of a guess, but in looking at the definition of recvmmsg:
extern int recvmmsg (int __fd, struct mmsghdr *__vmessages,
unsigned int __vlen, int __flags,
__const struct timespec *__tmo);
note that it takes a struct mmsghdr as an argument. However, while this prototype is unconditional, struct mmsghdr is only defined if __USE_GNU is set:
#ifdef __USE_GNU
/* For `recvmmsg'. */
struct mmsghdr
{
struct msghdr msg_hdr; /* Actual message header. */
unsigned int msg_len; /* Number of received bytes for the entry. */
};
#endif
-combine is basically equivalent to concatenating all your files together and then compiling them. Is there any chance that between the text of wrapunix.c and wrapsock.c that GNU_SOURCE is being defined? If that happened, then the first definition of recvmmsg would use a definition of struct mmsghdr that was local to just the prototype, while the second definition would use the real struct. Those two definitions would then be incompatible, which would result in the error message that you got.

Undefined Reference? But I've already implemented the function

display.h
#ifndef PRO_DISPLAY_H
#define PRO_DISPLAY_H
/** Initializes the display **/
int pro_display_init(void);
#endif /* PRO_DISPLAY_H */
display.c
#include "main.h"
static int height_ = 300;
static int width_ = 300;
static int bpp_ = 16;
static SDL_Surface* screen_ = NULL;
int pro_display_init(void)
{
screen_ = SDL_SetVideoMode(width_, height_, bpp_, SDL_HWSURFACE|SDL_DOUBLEBUF);
if (!screen_)
{
pro_sdl_error("Video initialization failed.");
return 0;
}
return 1;
}
main.h
#ifndef PRO_MAIN_H
#define PRO_MAIN_H
// standard headers
#include <stdlib.h>
#include <stdlib.h>
// conditional headers
#if defined(WIN32) || defined(_WIN32)
#include <windows.h>
#endif
// our own headers
#include "scripter.h"
#include "ttf_util.h"
#include "events.h"
#include "display.h"
// some macros
#define pro_error(...) fprintf(stderr, __VA_ARGS__)
#define pro_sdl_error(x) fprintf(stderr, "%s. \n=> %s\n", x, SDL_GetError())
#define pro_ttf_error(x) fprintf(stderr, "%s. \n=> %s\n", x, TTF_GetError())
#endif /* PRO_MAIN_H */
** main.c**
#include "main.h"
int main(int argc, char* argv[])
{
pro_display_init();
return 0;
}
The Error:
main.c|5|undefined reference to `pro_display_init()'|
Checked the build process. Made sure I was adding "display.c" to gcc's input files. I'm at my wit's end. Why the error?
display.c and main.c are compiled into their own "translation unit". What happens is that when trying to resolve symbols name (i.e. looking for pro_display_init), the C compiler thinks it's compiling a standalone .c unit. The proper way to go is to compile them separately and then link them, e.g.
gcc -c display.c # creates display.o
gcc main.c display.o # compiles main.o and then link with display.o
Of course, you'll be creating/reusing a Makefile soon that lets you define rules for all this.
I think, #include "main.h" or #include "display.h" (in main.h) "finds" the wrong include file. Check you include_path variable.

Resources