understanding fs/binfmt_elf.c - c

i am trying to understand the linux source file /home/akash/Downloads/linux-3.4.3/fs/binfmt_elf.c a part a code is as follows where i hv stuck.
static struct linux_binfmt elf_format = {
.module = THIS_MODULE,
.load_binary = load_elf_binary,
.load_shlib = load_elf_library,
.core_dump = elf_core_dump,
.min_coredump = ELF_EXEC_PAGESIZE,
};
which refer to the file include/linux/binfmt.h
struct linux_binfmt {
struct list_head lh;
struct module *module;
int (*load_binary)(struct linux_binprm *, struct pt_regs * regs);
int (*load_shlib)(struct file *);
int (*core_dump)(struct coredump_params *cprm);
unsigned long min_coredump; /* minimal dump size */
};
plz giv some explaination on this..

It is the initialisation of a structure of type struct linux_binfmt named elf_format (with static storage duration, meaning it exists for the lifetime of the program and is initialised exactly once), using syntax introduced in C99 that allows the specific structure member being initialised to be specified. Prior to C99 the initializer of a struct required the values to be listed in the order the members are declared in the struct.
For example:
struct struct_a { int a; char c; };
In C89 it was not possible to explicitly initialise c only:
struct struct_a s = { 0, 'f' }; /* Have to provide an initial value for
'a', the 0, in order to provide an
initial value for 'c', the f. */
but in C99 the new syntax made it possible:
struct struct_a s = { .c = 'f' };
The types of struct members:
lh is of type struct list_head, which is not explicitly initialised. lh will be default initialised (any members of lh that are pointers are initialized to a null pointer and any arithmetic types will be initialized to zero).
module is of type struct module* and is initialised to THIS_MODULE.
load_binary is a pointer to a function that returns an int and takes arguments of type struct linux_binptrm* and struct pt_regs, and is initialised to a function called load_elf_binary.
load_shlib is a pointer to a function that returns an int and takes an argument of type struct file* and is initialised to a function called load_elf_library.
core_dump is a pointer to a function that returns an int and takes an argument of struct coredump_params* and is initialised to a function called elf_core_dump.
min_coredump is of type unsigned long and is initialised to ELF_EXEC_PAGESIZE.
Refer to section 6.7.8 Initialization of the C99 standard for a full description on initialization syntax and rules.

elf_format is a variable of type linux_binfmt declared as static.
Values assigned for the members of elf_format
.module = THIS_MODULE,
.load_binary = load_elf_binary, /* Function pointer assigned with functions */
.load_shlib = load_elf_library, // do --
.core_dump = elf_core_dump, // do --
.min_coredump = ELF_EXEC_PAGESIZE,

Related

"Inheritance" in C's structs?

Here I'm a bit confused about this code:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
struct test_struct {
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
printf("%u\n", test_in.weird[0]); // 0
test_in.tst.weird[0] = 1;
printf("%u\n", test_in.weird[0]); // 1
return 0;
}
I didn't know that it is possible to use struct's fields this way, so I have two questions:
How is it called in C?
And, of course, how does it work? (Why weird field was changed when I don't change it directly, I thought these are two different fields?)
Here I'm a bit confused about this code:
The short answer is: the code has undefined behavior.
How is it called in C? How does it work?
struct test_struct is defined with its last member as an array of unspecified length: uint8_t weird[]; This member is called a flexible array member, not to be confused with a variable length array.
6.7.2 Type specifiers
[...]
20     As a special case, the last member of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
if you allocate such a structure from the heap with extra space for array elements, these elements can be accessed via the weird member up to the number of elements thus allocated.
The C Standard mandates that such a structure can only be defined as a member of another structure or union if it appears as the last member of said aggregate. In the posted code, the programmer violates this constraint, so accessing elements of test_in.tst.weird has undefined behavior, and so does accessing elements of test_in.weird.
The programmer also assumes that the test_in.tst.weird array and the test_in.weird array overlap exactly, which may be the case but is not guaranteed, nor supported: code relying on this type of aliasing has undefined behavior as well.
In your example, assuming the compiler accepts the empty initializer {} (part of the next C Standard and borrowed from C++), it seems to work as expected, but this is not guaranteed and alignment issues may cause it to fail as shown in the modified version below:
#include <stdint.h>
#include <stdio.h>
struct test_struct {
uint8_t f;
uint8_t weird[];
};
struct test_struct1 {
int x;
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
struct {
struct test_struct1 tst;
uint8_t weird[256];
} test_in1 = {};
printf("modifying test_in.weird[0]:\n");
printf("%u\n", test_in.weird[0]); // 0
test_in.tst.weird[0] = 1;
printf("%u\n", test_in.weird[0]); // 1
printf("modifying test_in1.weird[0]:\n");
printf("%u\n", test_in1.weird[0]); // 0
test_in1.tst.weird[0] = 1;
printf("%u\n", test_in1.weird[0]); // 0?
return 0;
}
Output:
chqrlie$ make 220930-flexible.run
clang -O3 -std=c11 -Weverything -o 220930-flexible 220930-flexible.c
220930-flexible.c:17:28: warning: field 'tst' with variable sized type 'struct test_struct' not at
the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
struct test_struct tst;
^
220930-flexible.c:19:17: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
} test_in = {};
^
220930-flexible.c:22:29: warning: field 'tst' with variable sized type 'struct test_struct1' not
at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
struct test_struct1 tst;
^
220930-flexible.c:24:18: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
} test_in1 = {};
^
4 warnings generated.
modifying test_in.weird[0]:
0
1
modifying test_in1.weird[0]:
0
0
struct test_struct {
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
Effectively, before there were FAM's in the language, what you've declared is:
int main(void) {
struct {
struct { uint8_t f; } tst;
union {
uint8_t weird0[1]; // any non-zero size up to 256
uint8_t weird1[256];
} overlay;
} test_in = {};
On the contrary as described in the comments section above, a declaration like
int array[];
is not a Variable Length Array, it's either called Arrays of unknown size (cppreference) or Arrays of Length Zero (gcc).
An example of a VLA would be:
void foo(size_t n)
{
int array[n]; //n is not available at compile time
}
Based on the comment below (from the cppreference - see provided link):
Within a struct definition, an array of unknown size may appear as the last member (as long as there is at least one other named member), in which case it is a special case known as flexible array member. See struct (section Explanation) for details:
struct s { int n; double d[]; }; // s.d is a flexible array member
struct s *s1 = malloc(sizeof (struct s) + (sizeof (double) * 8)); // as if d was double d[8]
The provided code is just invalid.
You declared a structure with a flexible array member
struct test_struct {
uint8_t f;
uint8_t weird[];
};
From the C Standard (6.7.2.1 Structure and union specifiers)
18 As a special case, the last element of a structure with more than
one named member may have an incomplete array type; this is called a
flexible array member.
As it is seen from the quote such a member must be the last element of a structure. So the above structure declaration is correct.
However then in main you declared another unnamed structure
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
//...
that contains as member an element of the structure with the flexible array element that now is not the last element of the unnamed structure. So such a declaration is invalid.
Secondly, you are using empty braces to initialize an object of the unnamed structure. Opposite to C++ in C you may not use empty braces to initialize objects.

How to access enum defined within a struct in C program

I am new to the C language and struggling with how to access enum's within a struct.
My code is the following:
bankHeader.h File
struct bankAcct{
int amount;
enum typeOfAcc{chck = 0, saving = 1};
int balance;
}
bank.c File
#include <stdio.h>
#include "bankHeader.h"
struct bankAcct test;
test.amount=100;
// I want to be able to get the value within my typeOfAcc
// example something like test.typeOfAcct = "chck" should return 0;
I reviewed some of the forms but I dont see anything that was easy to understand or worked.
If the enum is meant to be local to the struct, use an anonymous enum:
struct bankAcct{
int amount;
enum {chck = 0, saving = 1} type_of_acct;
int balance;
};
You could also put a tagged enum inside the struct:
struct bankAcct{
int amount;
enum typeOfAcc {chck = 0, saving = 1} type_of_acct;
//^this misleadingly puts `enum typeOfAcc` in filescope
int balance;
};
but a tagged (as opposed to an anonymous one) inner definition of an enum (or struct or union) will be hoisted. In effect, the latter snippet is just a confusing way of doing:
enum typeOfAcc {chck = 0, saving = 1};
struct bankAcct{
int amount;
enum typeOfAcc type_of_acct;
int balance;
};
Note that as peter-reinstate-monica points out in his comment below, the chck and saving constants will be "hoisted" regardless of whether or not you choose to use an anonymous embedded enum type.
Every field in your struct declaration is in the form
type fieldName;
With
enum typeOfAcc{chck = 0, saving = 1};
you have specified the type... but not the field name. That's just like defining a structure in this way
struct foo {
int;
}
So, basically, what you need is a field name:
struct bankAcct{
int amount;
enum typeOfAcc{chck = 0, saving = 1} type;
int balance;
}
You will be able to access it with
struct bankAcct var;
printf("%d\n", var.type);
Addendum
I would not recommend defining an enumeration inside a struct, first of all for readability reasons. Another reason might be incompatibility with C++: I wasn't able to compile an example C++ code in which the symbols of the inner enum were accessed. The following assignment
struct bankAcct var;
var.type = chck;
raised an error on gpp because the symbol chck could not be referenced outside the struct definition scope. Even assigning an integer to the enum field lead the compiler to complain, and I could not even perform the casting
b.type = (enum typeOfAcc) 1;
because an error was raised: the enum typeOfAcc wasn't be accessible as well.
But in C these assignments would be ok, and both enum tags and constant identifiers (named and anonymous) would be "reachable". As explained in C specification 6.2.1§4, the scope of an identifier outside any code block is the whole translation unit:
Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit.
Just for completeness, after saying where the scope ends, we must say where the scope begins (C specification 6.2.1§7):
Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. Any other identifier has scope that begins just after the completion of its declarator.
You should declare the enum type outside the structure, then declare a member variable with that type.
typedef enum {
chck = 0,
saving = 1
} accountType;
struct bankAcct{
int amount;
accountType typeOfAcc ;
int balance;
}

local static variable initialization by using global struct address values

My aim is to initialize a local static int variable.
I want to initialize my variable with the value that equals to offset value of a struct member.
My struct definition
struct member{
int ID;
char *NAME;
int NO;
};
Global Struct declaration
struct member FirstMember={.ID = 123, .NAME ="John", .NO=7382737};
struct member SecondMember={.ID = 120, .NAME ="Bill", .NO=454545};
Function and local static variable declaration
void foo()
{
static int offset = (int)(&FirstMember.NO - &SecondMember.ID );
}
Compiler output: Error[Pe028]: expression must have a constant value..
As far as I know static local variables must be initialized with const values. Compiler also knows the address values of the struct and its members. So compiler is able to calculate the difference between member addresses. But it returns an error message.
But this initialization works
void foo()
{
static int offset = (int)(&FirstMember.NO - &FirstMember.ID );
}
Could you please explain the point that I missed?
I think the problem is in your structure declaration: Name shoul be "char *" not "char" because you try to initialize it with "John" (type const char *).
This is working for me:
struct member{
int ID;
char* NAME;
int NO;
};
struct member FirstMember={123,"John",7382737};
void foo()
{
static int offset = (int)(&FirstMember.NO - &FirstMember.ID );
}
The second problem is that you want to initialize a "static" variable with an unknown value before run time.
All the static variables are in a separate place named "initialized data" section and the compiler needs to know exactly the value of each static variable at compile time because these values are "hardcoded" inside your binary file.
Even for this code:
int a = 10;
static int x = a;
you will have the same problem because "a" is not evaluated at compile time but at run-time.

what's the meaning of the '.' in the struct [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What means the dot before variable name in struct?
const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek,
.read = do_sync_read,
// ....other stuffs
};
my question is :
1) what is the meaning of .llseek and how to use ....the file_operations struct definition is below:
2) can I just say : llseek = generic_file_llseek ; in the struct above to let the pointer llseek points to generic_file_llseek without putting the dot . before llseek?
//sorry for my poor english
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//....other stuffs
}
It's a special structure initialization syntax that has been introduced in c99.
When you have .llseek = generic_file_llseek, inside your structure initializer, this means you are initializing this particular member regardless of its offset relative to the structure beginning.
Alternatively you can use an initialization without designators, but you will have to put the initializers in the exact order as the corresponding fields in the structure are declared.
const struct file_operations generic_ro_fops = {
generic_file_llseek, // this initializes llseek member
do_sync_read, // this initializes read member
// ....other stuffs
};
This is called designated initializers. You are initializing exact member/field of the structure.
2.can i just say : "llseek = generic_file_llseek ;" in the struct above to let the pointer llseek points to generic_file_llseek without
putting the dot '.' before llseek?
No
You can do something like this to initialize members:
const struct file_operations generic_ro_fops = {
generic_file_llseek,
do_sync_read,
// ....other stuffs
};
but in this case you will have to initialize everything in order like members are placed inside structure. Designated initializers are very helpful when you want to initialize just some of structure fields.
You can use something like this outside structure:
generic_ro_fops.llseek = generic_file_llseek;
The meaning of the '.' in that struct is called a designated initializer. In the struct, each '.' represents member of the struct which needs to be initialized, thus being called a designator.
Meaning
1) what is the meaning of .llseek and how to use ....the file_operations struct definition is below:
It is a C99 feature: designated initializers. With the . you can initialize a given field of your structure. Here, it is necessary to initialize your structure cause of the const qualifier.
If lseek and read are in this order in the structure definition, you can ommit this designator.
const struct file_operations generic_ro_fops = {
generic_file_llseek,
do_sync_read
};
This last method is not very maintenable (if you change the order of your structure's fields, you have to change all your initialization code), therefore the method with designated iniitializers is better, here.
Other manner
2) can I just say : llseek = generic_file_llseek ; in the struct above to let the pointer llseek points to generic_file_llseek without putting the dot . before llseek? //sorry for my poor english
No, you can't, because it is not the right syntax.
References
C11 (n1570), § 6.7.9 Initialization
If a designator has the form
. identifier
then the current object (defined below) shall have structure or union
type and the identifier shall be the name of a member of that type.

How to apply the sizeof operator to a function pointer and initialize a structure?

The folowing piec of code generates error: initializer element is not constant
at compile time on the line declaring and initializing the user struct variable.
#include <stdio.h>
#include <stdlib.h>
struct user_s {
char *name;
void (*(*pred_skip_func))(int);
};
void f1 (int skip) {
printf("I am f1\n");
}
void f2 (int skip) {
printf("I am f2\n");
}
void (*(*pred_skip_func))(int);
struct user_s user = {"Manu", pred_skip_func};
int main(void) {
struct user_s tmp;
pred_skip_func = malloc(sizeof(tmp.pred_skip_func) * 2);
pred_skip_func[0] = f1;
pred_skip_func[1] = f2;
int i;
for (i = 0; i < 2; i++) {
(*(user.pred_skip_func)[i]) (i);
}
return EXIT_SUCCESS;
}
Moving the initialization in the main function solves the issue, but I want to understand why ? Is there any restriction on structure initialisation ?
More over, as you can see, I created a tmp user_struc variable to get the size of my pointer to function pointers because I was not able to do this in a cleaner way. How can I fix this ?
First question:
"Is there any restriction on structure initialisation ?"
C requires initializers for aggregate types with static storage duration to be constant:
(C99, 6.7.8p4) "All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals."
Note that in C89 even if the object of the aggregate type had automatic storage duration the intializers had to be constant expressions (this is no longer the case in C99).
Second question:
"More over, as you can see, I created a tmp user_struc variable to get the size of my pointer to function pointers because I was not able to do this in a cleaner way."
You can use your user object to compute the size of the member:
sizeof (user.pred_skip_func)
or use a C99 compound literal if you have not declared any object of the structure type:
sizeof (((struct user_s) {0}).pred_skip_func)
As #ouah points out, the problem is that pred_skip_func is not a constant value. The compiler complains because user has static storage duration, which means its bitwise representation is going to be "baked in" the executable image at link time. In order for this representation to be known to the linker the value for pred_skip_func must be a constant.
However, you can specify a "sane default" constant value for the struct member very easily:
struct user_s user = {"Manu", 0};
You can go for typedefs for function pointer like below.
typedef void (*pfunc_type)(int);
struct user_s
{
char *name;
pfunc_type *pred_skip_func;
};
.....
int main (void)
{
.....
pred_skip_func = (pfunc_type *)malloc(sizeof(pfunc_type) * 2);
.....
}
This will increase the readablity of your program.

Resources