For a homework assignment, I have to modify the linux kernel.
I am working on a virtual machine, and I added a system call to the kernel, which I called get_unique_id. Here is the code for get_unique_id.c :
#include <linux/linkage.h>
#include <asm/uaccess.h>
asmlinkage long sys_get_unique_id(int * uuid)
{
// static because we want its state to persist between calls
static int uid = 0;
++uid;
// assign new uid value to user-provided mem location
// returns non-zero if success or -EFAULT otherwise
int ret = put_user(uid, uuid);
return ret;
}
I also added this line to syscalls.h :
asmlinkage long sys_get_unique_id(int * uuid);
This line to syscall_32.tbl :
383 i386 get_unique_id sys_get_unique_id
And finally this line to syscall_64.tbl :
548 common get_unique_id sys_get_unique_id
After recompiling and reloading the kernel, I wrote a little C program to test my system call, here is the code for the C test file :
// get_unique_id_test.c
#include <stdio.h>
#include <limits.h>
#include "syscalls_test.h"
int main(void)
{
// initialize the ints we want
int id1;
int id2;
// check the id's are unique and that no error occured
for (int i = INT_MIN; i < INT_MAX - 1; i += 2) {
long ret1 = get_unique_id(&id1);
long ret2 = get_unique_id(&id2);
if (ret1 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret1);
if (ret2 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret2);
if (id2 != id1 + 1)
printf("ERROR: successive id's did not increment properly: id1 = %d, id2 = %d\n", id1, id2);
}
return 0;
}
And its header file :
// syscalls_test.h
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define __NR_get_unique_id 383
inline long get_unique_id(int * uuid)
{
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
}
Unfortunately, while trying to compile the C test file with the following command : gcc -std=c99 get_unique_id_test.c -o get_unique_id_test, I get the following error :
In file included from get_unique_id_test.c:4:0:
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
/tmp/cc1euZ3r.o: In function `main':
get_unique_id_test.c:(.text+0x22): undefined reference to `get_unique_id'
get_unique_id_test.c:(.text+0x34): undefined reference to `get_unique_id'
collect2: error: ld returned 1 exit status
It appears gcc cannot find the function get_unique_id(int * uuid), which is declared in syscalls_test.h, and the syscall function, which should be declared, I believe, in syscall.h, right ?
I don't understand why this happens. Does anybody have an idea ?
EDIT : my problems were solved using a3f's solution (see below) PLUS moving the #include "syscalls_test.h" at the very top of the file, as he said in the comments. Thank you very much.
#define _GNU_SOURCE before including unistd.h or any other header as syscall(2) is not POSIX.
Use static inline instead of plain inline. Plain inline supplies an inline definition, but the compiler is free to ignore it and use the external definition instead, which you aren't providing.
Try the following one:
#include <unistd.h>
Related
I would like to get the value of the PID_MAX macro present in the file /sys/sys/proc.h.
My current code (main.c) :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* type pid_t */
#include <sys/proc.h> /* macro PID_MAX */
#include <sys/unistd.h> /* function getpid, getppid */
/*
gcc -Wall -Wextra main.c -o main
./main
*/
int main ()
{
pid_t pidmax = PID_MAX;
printf ( "Value = %d\n", pidmax );
return 0;
}
Return the following error :
error: 'PID_MAX' undeclared (first use in this function); did you mean 'UID_MAX'?
How is it possible?
Another method to recover the PID_MAX?
There is no platform-independent method for retrieving the maximum pid value.
Under Linux, for example, you can determine the value through the /proc/sys interface
$ sysctl kernel/pid_max
32768
Under FreeBSD, the value is 99999. If you look closely in sys/proc.h, you will notice that the macro PID_MAX is guarded by
#ifdef _KERNEL
...
#define PID_MAX 99999
...
#endif
This is, why you cannot (and should not) use it in userspace programs.
The PID_MAX macro defines the hard limit of PID values by BSD kernels (such as kFreeBSD); it shouldn't be used by user space programs because the actual maximum PID value could be further lowered in the runtime, controlled by kern.pid_max sysctl.
To get such runtime limitation in an user space program, use sysctlbyname(3); for example:
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
int main() {
int pid_max;
size_t len = sizeof pid_max;
if(sysctlbyname("kern.pid_max", &pid_max, &len, NULL, 0) < 0) {
perror("sysctlbyname: kern.pid_max");
return 1;
}
printf("kern.pid_max=%d\n", pid_max);
return 0;
}
error occurs while compiling the following c code on CentOS release 4.3.
#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
union {
uint32_t u32;
uint8_t arr[4];
} x;
x.arr[0] = 0x11;
x.arr[1] = 0x22;
x.arr[2] = 0x33;
x.arr[3] = 0x44;
printf("x.u32 = 0x%x\n", x.u32);
printf("htole32(x.u32) = 0x%x\n", htole32(x.u32));
printf("htobe32(x.u32) = 0x%x\n", htobe32(x.u32));
exit(EXIT_SUCCESS);
}
Details of compiling errors:
$ gcc a.c /tmp/ccki8bVg.o(.text+0x3a): In function main': :
undefined reference tohtole32' /tmp/ccki8bVg.o(.text+0x58): In
function main': : undefined reference tohtobe32' collect2: ld
returned 1 exit status
It seems that there isn't htole32 and htobe32 on my server.
$ man htole32
No manual entry for htole32
The manual page actually has:
#define _BSD_SOURCE
before the #include <endian.h>. It only has that in the top section though, not in the example program below. Of course, since your target system doesn't even have the manual page, that might imply it has a runtime environment which doesn't implement this (non-standard) part.
I have second level include that is giving me grief:
Undefined first referenced
symbol in file
function2 /var/tmp//ccAPaWbT.o
ld: fatal: symbol referencing errors. No output written to run
collect2: ld returned 1 exit status
Main file:
#include "functions02.c"
int main(){
int x = funcion2();
}
functions02.c file:
#ifndef FUNCTIONS02_C
#define FUNCTIONS02_C
int funcion2();
#if __INCLUDE_LEVEL__ == 0
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include "functions01.c"
int main() {
return function2();
}
#endif
int function2()
return function1();
}
#endif
functions01.c file:
#ifndef FUNCTIONS01_C
#define FUNCTIONS01_C
int funcion1();
#if __INCLUDE_LEVEL__ == 0
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main() {
return function1();
}
#endif
int function1()
return 10;
}
#endif
I am assuming that this can be fixed manipulated using __INCLUDE_LEVEL__ or manipulating linking on gcc compiling but I can't find forking variant.
First of all is it possible to achieve what I am looking for without putting functions in external header files?
Second what would be the correct way of doing it?
EDIT:
I realized that I had forgotten to add function dependencies to them. That is the includes which are used by functions can not be excluded by adding them just next to main function warped in exclusion if close.
Yes, it is possible to include / exclude any part of the code using compile time flags (and in the code using #if's) as you are trying to do.
In your case, I assume you have not defined __INCLUDE_LEVEL__ flag, hence the linker is not able to find funciton2, so the error.
If you define it, you will have three "main()" :-), it will fail again. So, you need to rework your code a bit.
Also, #include'ing a "C" file is not advisable and not used in practice. I assume you are just trying to experiment & learn, which is fine.
So I have this very simple program but I can't seem to get rid of a simple error.
I have a Header file with this
#ifndef FUNCTIONLOOKUP_H_INCLUDED
#define FUNCTIONLOOKUP_H_INCLUDED
enum functions
{
foo,
bar
};
//predefined function list
int lookUpFunction(enum functions);
#endif // FUNCTIONLOOKUP_H_INCLUDED
And in the src file i have the definition of lookUpFunction
Now when I call the lookUpFunction() from my main where I included the header file it gives me a undefined reference to it. The other awnsered questions where of no help.
#include <stdio.h>
#include <stdlib.h>
#include "FunctionLookUp.h"
int main()
{
lookUpFunction(foo); <---
return 0;
}
Function implementation
#include <stdio.h>
#include "FunctionLookUp.h"
typedef void (*FunctionCallback)(int);
FunctionCallback functionList[] = {&foo, &bar};
void foo(int i)
{
printf("foo: %d", i);
}
void bar(int i)
{
printf("bar: %d", i);
}
int lookUpFunction(enum functions)
{
int test = 2;
//check if function ID is valid
if( functions >= sizeof(functionList))
{
printf("Invalid function id"); // error handling
return 0;
}
//call function
functionList[functions](test);
return 1;
}
I can't seem to figure out where this error comes from.
You must have some file similar to:
/* FunctionLookUp.c */
#include "FunctionLookUp.h"
int lookUpFunction(enum functions)
{
/* code ... */
return x;
}
somewhere in order to solve your problem
You never show code that implements the function.
So it's most likely that what you're seeing is a linker error, the call itself is fine but the linker cannot find the code to call, so it throws an error.
Just declaring a function can't magically make it appear from somewhere, you must write the actual function too.
I want to manipulate Stdin and then Std*. But I am getting the following errors,
$ gcc testFd.c
testFd.c:9: error: initializer element is not constant
testFd.c:9: warning: data definition has no type or storage class
testFd.c:10: error: redefinition of `fd'
testFd.c:9: error: `fd' previously defined here
testFd.c:10: error: `mode' undeclared here (not in a function)
testFd.c:10: error: initializer element is not constant
testFd.c:10: warning: data definition has no type or storage class
testFd.c:12: error: syntax error before string constant
The program is shown below.
#include <stdio.h>
#include <sys/ioctl.h>
int STDIN_FILENO = 1;
// I want to access typed
// Shell commands, dunno about the value:
unsigned long F_DUPFD;
fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
fd = open("/dev/fd/0", mode);
printf("STDIN = %s", fd);
Updated Errors: just trying to get an example program about file descriptors to work in C, pretty lost with the err report
#include <stdio.h>
#include <sys/ioctl.h>
int main (void) {
int STDIN_FILENO;
// I want to access typed
// Shell commands, dunno about the value:
unsigned long F_DUPFD;
int fd;
const char mode = 'r';
fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
/* also, did you mean `fopen'? */
fd = fopen("/dev/fd/0", mode);
printf("STDIN = %s", fd);
return 0;
}
The program execution is shown below.
$ gcc testFd.c
testFd.c: In function `main':
testFd.c:14: warning: passing arg 2 of `fopen' makes pointer from integer without a cast
testFd.c:14: warning: assignment makes integer from pointer without a cast
Try using a main method:
#include <stdio.h>
#include <sys/ioctl.h>
int main (void) {
int STDIN_FILENO = 1;
// I want to access typed
// Shell commands, dunno about the value:
unsigned long F_DUPFD;
/* also, declare the type of your variable "fd" */
int fd;
fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
/* also, did you mean `fopen'? */
fd = open("/dev/fd/0", mode);
printf("STDIN = %s", fd);
return 0;
}
You forgot your main() function!!
Where's your definition of main()?
Quite apart from the fact that you don't have a main() function, your entire approach is wrong. STDIN_FILENO is a constant; assigning to it doesn't make any sense.
Try explaining what you actually want to do, with some detail, and we will be able to suggest how to go about it.