As we all know when using EXPORT_SYMBOL("function name") we get into the symbol list in System.map the function name as symbol.
c041bc90 b packet_sklist
c041bc94 b packet_sklist_lock
c041bc94 b packet_socks_nr
c041bc98 A __bss_stop
c041bc98 A _end
c041c000 A pg0
ffffe400 A __kernel_vsyscall
My question is: is there any compile option, hacking, macro or anything in the world enables you to include also the arguments of the function ?
i.e
c041bc90 b packet_sklist (list of arguments...)
two reasons for these:
you can export do_something(int a) and export do_something(int a,int b) .
you won't have bugs when using extern functions in kernel modules
which have mismatch in the arguments.
The no 1 reason you've shown, even if EXPORT_SYMBOL supports argument, it won't support variable argument, cause Linux uses C.
Related
This question already has answers here:
How Get arguments value using inline assembly in C without Glibc?
(3 answers)
Closed 2 years ago.
Can I get argv[0] through _start instead of main in the C function? I don't use any lib.
void _start(void) __attribute__((noreturn));
void _start(void)
{
//how can get argv[0] here . I don't use main as my first entry.
}
The ELF entry point contract is not a C function in the vast majority of psABIs (processor-specific ABI, the arch-dependent part of ELF). At entry, the stack pointer register points to an array of system-word-sized slots consisting of:
argc, argv[0], ..., argv[argc-1], 0, environ[0], ..., environ[N], 0,
auxv[0].a_type, auxv[0].a_value, ..., 0
You need at least a minimal asm stub to convert this into form that's readable by C. The simplest way to do this is to copy the stack pointer register into the first-argument register, align the stack pointer down according the function call ABI requirements, and call your C function taking a single pointer argument.
You can see the crt_arch.h files (x86_64 version here) in musl libc for an example of how this is done. (You can probably ignore the part about _DYNAMIC which is arranging for self-relocation when the entry point is used in the dynamic linker startup or static PIE executables.)
In C it is an idiomatic pattern to have your .h file contain declarations of the externally visible symbols in the corresponding .c file. The purpose if this is to support a kind of "module & interface" thinking, e.g enabling a cleaner structure.
In a big legacy C system I'm working on it is not uncommon that functions are declared in the wrong header files probably after moving a function to another module, since it still compiles, links and runs, but that makes the modules less explicit in their interfaces and indicates wrong dependencies.
Is there a way to verify / confirm / guarantee that the .h file has all the external symbols from .c and no external symbols that are not there?
E.g. if I have the following files
module.c
int func1(void) {}
bool func2(int c) {}
static int func3(void) {}
module.h
extern int func1(void);
extern bool func4(char *v);
I want to be pointed to the fact that func4 is not an external visible symbol in module.c and that func2 is missing.
Modern compilers give some assistance in as so much that they can detect a missing declaration that you actually referenced, but it does not care from which file it comes.
What are my options, other than going over each pair manually, to obtain this information?
I want to be pointed to the fact that func4 is not an external visible symbol in module.c and that func2 is missing.
Using POSIX-ish linux with bash, diff and ctags and given really simple example of input files, you could do this:
$ #recreate input
$ cat <<EOF >module.c
int func1(void) {}
bool func2(int c) {}
static int func3(void) {}
EOF
$ cat <<EOF >module.h
extern int func1(void);
extern bool func4(char *v);
EOF
$ # helper function for extracting only non-static function declarations
$ f() { ctags -x --c-kinds=fp "$#" | grep -v static | cut -d' ' -f1; }
$ # simply a diff
$ diff <(f module.c) <(f module.h)
2,3c2
< func2
---
> func4
$ diff <(f module.c) <(f module.h) |
> grep '^<\|^>' |
> sed -E 's/> (.*)/I would like to point the fact that \1 is not externally visible symbol/; s/< (.*)/\1 is missing/'
func2 is missing
I would like to point the fact that func4 is not externally visible symbol
This will break if for example static keyword is not on the same line as function identifier is introduced, because ctags will not output it them. So the real job of this is getting the list of externally visible function declarations. This is not an easy task and writing such tool is left to others : )
It does not make any sense as if you call not defined function, the linker will complain.
More important is to have all functions prototypes - as compiler has to know how to call them. But in this case compilers emit warnings.
Some notes: you do not need the keyword extern as functions are extern by default.
This is the time to shine for some of my favorite compiler warning flags:
CFLAGS += -Wmissing-prototypes \
-Wstring-prototypes \
-Wmissing-declarations \
-Wold-style-declaration \
-Wold-style-definition \
-Wredundant-decls
This at least ensures, that all the source files containing implementations of a function that is not static also have a previous external declaration & prototype of said function, ie. in your example:
module.c:4:6: warning: no previous prototype for ‘func2’ [-Wmissing-prototypes]
4 | bool func2(int c) { return c == 0; }
| ^~~~~
If we'd provide just a forward declaration that doesn't constitute a full prototype we'd still get:
In file included from module.c:1:
module.h:7:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
7 | extern bool func2();
| ^~~~~~
module.c:4:6: warning: no previous prototype for ‘func2’ [-Wmissing-prototypes]
4 | bool func2(int c) { return c == 0;}
| ^~~~~
Only providing a full prototype will fix that warning. However, there's no way to make sure that all declared functions are actually also implemented. One could go about this using linker module definition files, a script using nm(1) or a simple "example" or unit test program, that includes every header file and tries to call all functions.
To list the differences between the exported symbols in a .c module in C and the corresponding .h file you can use chcheck. Just give the module name on the command line
python3 chcheck.py <module>
and it will list what externally visible functions are defined in the .c module but not exposed in the .h header file, and if there are any functions in the header module that are not defined in the corresponding .c file.
It only checks for function declarations/definitions at this point.
Disclaimer I wrote this to solve my own problem. Its built in Python on top of #eliben:s excellent pycparser.
Output for the example in the question is
Externally visible definitions in 'module.c' that are not in 'module.h':
func2
Declarations in 'module.h' that have no externally visible definition in 'module.c':
func4
In computer software, an application binary interface (ABI) is an interface between two binary program modules; often, one of these modules is a library or operating system facility, and the other is a program that is being run by a user.
An ABI defines how data structures or computational routines are accessed in machine code, which is a low-level, hardware-dependent format; in contrast, an API defines this access in source code, which is a relatively high-level, relatively hardware-independent, often human-readable format. A common aspect of an ABI is the calling convention, which determines how data is provided as input to or read as output from computational routines; examples are the x86 calling conventions.
-- https://en.wikipedia.org/wiki/Application_binary_interface
I am sure that the standard "Function Calling Sequence" described in Sys V ABI specs (both i386 and AMD64) constraints the calling of those extern functions in a C library, but does it constraints the calling of those static functions too?
Here is an example:
$cat abi.c
#include<stdio.h>
typedef void (*ret_function_t)(int,int);
ret_function_t gl_fp = NULL;
static void prnt(int i, int j){
printf("hi from static prnt:%d:%d\n", i, j);
}
void api_1(int i){
gl_fp = prnt;
printf("hi from extern api_1:%d\n", i);
}
ret_function_t api_2(void){
return gl_fp;
}
$cat abi_main.c
#include<stdio.h>
typedef void (*ret_function_t)(int,int);
extern void api_1(int i);
extern ret_function_t api_2(void);
int main(){
api_1(1111);
api_2()(2222, 3333);
}
$gcc abi_main.c abi.c -o abi_test
$./abi_test
hi from extern api_1:1111
hi from static prnt:2222:3333
The function calling sequence (including registers usage, stack frame, parameters passing, variable arguments...) details are defined in the Sys V ABI when abi_main.c call the api_1 and api_2 since they are extern, but what about the calling of the static function prnt which been defined in abi.c? Does it belong to the ABI standard or to the compiler to decide?
Yes, they do apply. Static functions are just plain functions with traslation-unit visibility. The ABI is a compiler generation task, C standard deliberately says nothing about it. It becomes clear when removing the static word from your code. The reasoning is the same. The drawback with this approach is that compiler cannot check the linkage right (caller-callee), but only its type (void (*ret_function_t)(int,int);) at compile time, since you are the one who links at runtime. So, it is not recommended.
What happens is that your compiler will generate code for any calling function, following some ABI, lets call it ABI-a. And it will generate code for
a function being called according to some other ABI, lets say ABI-b. If ABI-a == ABI-b, that always work, and this is the case if you compile both files with the same ABI.
For example, this works if prnt function were located at address 0x12345678:
ret_function_t gl_fp = (ret_function_t)0x12345678;
It also works as long as there is a function with the right arguments at 0x12345678. As you can see, the function cannot be inlined because the compiler does not know which function definition will end up in that memory spot, there could be many.
I am trying to port some C code to a cuda kernel. The code I am porting uses ellipsis prevalently. When I try to use an ellipsis in a device function like below, I get an error saying that ellipsis are not allowed in device functions.
__device__ int add(int a, ...){}
However, cuda supports using printf in both host and device functions and uses ellipsis in their own code as below in common_functions.h.
extern "C"
{
extern _CRTIMP __host__ __device__ __device_builtin__ __cudart_builtin__ int __cdecl printf(const char*, ...);
extern _CRTIMP __host__ __device__ __device_builtin__ __cudart_builtin__ int __cdecl fprintf(FILE*, const char*, ...);
extern _CRTIMP __host__ __device__ __cudart_builtin__ void* __cdecl malloc(size_t) __THROW;
extern _CRTIMP __host__ __device__ __cudart_builtin__ void __cdecl free(void*) __THROW;
}
Is there a way to use ellipsis in a device function?
I would not like to hard code a max number of parameters and then change all the calls.
I also would not like to code a custom variadic function method.
I also tried creating a PTX file that I could use to replace the ellipsis usage as the ISA PTX documentation appears to have facilities for handling variable parameters (Note that the documentation says it does not support them and then provides a paragraph with supporting functions and examples. Perhaps, there is a typo?). I got a simple PTX file all the way through the process defined below but got stuck on the executable question in the last comment. I plan to read the nvcc compiler document to try and understand that.
How can I call a ptx function from CUDA C?
I am using a GTX660 which I believe is level 3.0 and cuda 5.0 toolkit on Ubuntu 12.04.
Update regarding the "magic" referred to below:
It looks to me like there must be something special happening in the compiler to restrict ellipsis usage and do something special. When I call printf as below:
printf("The result = %i from adding %i numbers.", result, 2);
I was surprised to find this in the ptx:
.extern .func (.param .b32 func_retval0) vprintf
(
.param .b64 vprintf_param_0,
.param .b64 vprintf_param_1
)
and later
add.u64 %rd2, %SP, 0;
st.u32 [%SP+0], %r5;
mov.u32 %r6, 2;
st.u32 [%SP+4], %r6;
// Callseq Start 1
{
.reg .b32 temp_param_reg;
.param .b64 param0;
st.param.b64 [param0+0], %rd1;
.param .b64 param1;
st.param.b64 [param1+0], %rd2;
.param .b32 retval0;
call.uni (retval0),
vprintf,
(
param0,
param1
);
It appears to me that the compiler accepts ellipsis for printf but then swaps a call to vprintf and creates a va_list on the fly manually. va_list is a valid type in device functions.
As #JaredHoberock stated (I think he will not mind if I create an answer):
__device__ functions cannot have ellipsis parameters; that is why you are receiving the compiler error message.
The built-in printf function is a special case, and does not indicate general support for ellipsis.
There are some alternatives that could be mentioned, but none that I am aware of allow truly general variable arguments support. For example, as Jared stated you could simply define a number of parameters, some/most of which have default values specified, so they do not need to be passed explicitly.
You could also play games with templating as is done in the cuPrintf sample code to try and simulate variable arguments, but this will also not be arbitrarily extensible, I don't think.
Folks,
I'm trying to hack a kernel module by modifying its symbol. The basic idea is to replace the original function with new function by overwriting its address in the symtab. However, I found when declaring the function as static, the hacking fails. But it works with non-static function. My example code is below:
filename: orig.c
int fun(void) {
printk(KERN_ALERT "calling fun!\n");
return 0;
}
int evil(void) {
printk(KERN_ALERT "===== EVIL ====\n");
return 0;
}
static int init(void) {
printk(KERN_ALERT "Init Original!");
fun();
return 0;
}
void clean(void) {
printk(KERN_ALERT "Exit Original!");
return;
}
module_init(init);
module_exit(clean);
Then I follow the styx's article to replace the original function "fun" in symtab to call function "evil", http://www.phrack.org/issues.html?issue=68&id=11
>objdump -t orig.ko
...
000000000000001b g F .text 000000000000001b evil
0000000000000056 g F .text 0000000000000019 cleanup_module
0000000000000036 g F .text 0000000000000020 init_module
0000000000000000 g F .text 000000000000001b fun
...
By executing the elfchger
>./elfchger -s fun -v 1b orig.ko
[+] Opening orig.ko file...
[+] Reading Elf header...
>> Done!
[+] Finding ".symtab" section...
>> Found at 0xc630
[+] Finding ".strtab" section...
>> Found at 0xc670
[+] Getting symbol' infos:
>> Symbol found at 0x159f8
>> Index in symbol table: 0x1d
[+] Replacing 0x00000000 with 0x0000001b... done!
I can successfully change the fun's symbol table to be equal to evil and inserting the module see the effects:
000000000000001b g F .text 000000000000001b evil
...
000000000000001b g F .text 000000000000001b fun
> insmod ./orig.ko
> dmesg
[ 7687.797211] Init Original!
[ 7687.797215] ===== EVIL ====
While this works fine. When I change the declaration of fun to be "static int fun(void)" and follows the same steps as mentioned above, I found the evil does not get called. Could anyone give me some suggestion?
Thanks,
William
Short version: Declaring a function as 'static' makes it local and prevents the symbol to be exported. Thus, the call is linked statically, and the dynamic linker does not effect the call in any way at load time.
Long Version
Declaring a symbol as 'static' prevents the compiler from exporting the symbol, making it local instead of global. You can verify this by looking for the (missing) 'g' in your objdump output, or at the lower-case 't' (instead of 'T') in the output of 'nm'. The compiler might also inline the local function, in which case the symbol table wouldn't contain it at all.
Local symbols have to be unique only for the translation unit in which they are defined. If your module consisted of multiple translation units, you could have a static fun() in each of them. An nm or objdump of the finished .ko may then contain multiple local symbols called fun.
This also implies that local symbols are valid only in their respective translation unit, and also can be referred (in your case: called) only from inside this unit. Otherwise, the linker just would not now, which one you mean. Thus, the call to static fun() is already linked at compile time, before the module is loaded.
At load time, the dynamic linker won't tamper with the local symbol fun or references (in particular: calls) to it, since:
its local linkage already done
there are potentially more symbols named 'fun' throughout and the dynamic linker would not be able to tell, which one you meant