If you want to get the Instruction Pointer (= program counter) in the Linux kernel driver, use the _THIS_IP_
macro defined in linux / kernel.h.
The definition is as follows.
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
In the past, each architecture defined its own current_text_addr ()
, but around v4.20 they were all abolished and unified to use _THIS_IP_
in linux / kernel.h. is.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v5.6-rc2&id=de0d22e50cd3d57277f073ccf65d57aa519d6888
Looking at the patch at this time, it is interesting to see how to get the program counter by the assembler of each architecture. As is obvious to anyone who has written assembler, the register that holds the program counter of the processor differs depending on the architecture. So it seems reasonable to have a separate implementation for each architecture. So why was it unified into one macro?
First of all, I couldn't understand the macro at all, so I googled it, and a gentle older brother explained it on stackoverflow. As expected.
https://stackoverflow.com/questions/13902431/this-ip-macro-in-linux-kernel
In summary,
__label__ __here;
is a declaration of the local label name__here:
is the local label&& __here;
is the address of the above local label (cast to unsigned long type)It seems that. It is difficult to understand if there is only one line in parentheses (), so if you insert a line break,
{
__label__ __here;
__here:
(unsigned long)&&__here;
}
The first line is the declaration of the local label name, and the second line is the label. The local label seems to work with GCC. https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Local-Labels.html
It's a label that can only be referenced within a block.
The'&&' on the third line is a special operator to indicate the label address (reference: https://docs.oracle.com/cd/E19205-01/821-0386/bjabt/index.html)
At the position where this macro is embedded, __here
is pasted as a local label in the block, and getting the address of that label is the current program position (= program counter) at the end.
Therefore, since the current position of the program can be expressed only in C language without relying on the assembler, it is possible to unify the current position of the program into one _THIS_IP_
macro even in the kernel. (In addition, as long as gcc is used, it should be portable to various environments, not limited to Linux.)
The problem is about this outside. I honestly don't know. Normally, the block statement {} cannot be used as an expression. As a test, if you write the following code, you will get a compile error.
int i = {1;};
However, if you enclose the block statement in parentheses (), it will compile for some reason.
int i = ({1;});
At this time, the value of the parenthesis () expression is the value when the expression written at the end of the block {} statement is evaluated. When I try to compile the following code with gcc and execute it, the value (= 5) of the expression d at the end of the block statement is displayed on the console.
#include <stdio.h>
int main(void)
{
int a = ({
int a = 2;
int b = 3;
int c = 4;
int d = 5;
a;
b;
c;
d;
});
printf("%d\n", a);
return 0;
}
How is this grammatically? .. ..
As mentioned above, I have been dealing with C language for more than 10 years, but I have summarized it as a memorandum because of the powerlessness that I still do not know or read grammatically. ... I will devote myself.
But I think ** C language is not beautiful **. Because'&&', you must have been dating me as a binary operator all the time ...? (Is'&&' also an extension of GCC? Https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Labels-as-Values.html#Labels-as-Values)
Recommended Posts