In Linux kernel linux/arch/x86/boot/main.c
, I found a piece of inline asm code:
asm("leal %P1(%%esp),%0"
: "=r" (stack_end) : "i" (-STACK_SIZE));
This code snippet is pretty simple, but %P1
confused me. I checked some assembly language tutorials, but found nothing about this.
So, can anyone give me some pieces of clue about this?
The __asm keyword invokes the inline assembler and can appear wherever a C or C++ statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces.
In computer programming, an inline assembler is a feature of some compilers that allows low-level code written in assembly language to be embedded within a program, among code that otherwise has been compiled from a higher-level language such as C or Ada.
The “r” in the operand constraint string indicates that the operand must be located in a register. The “=” indicates that the operand is written. Each output operand must have “=” in its constraint.
The asm statement allows you to include assembly instructions directly within C code. This may help you to maximize performance in time-sensitive code or to access assembly instructions that are not readily available to C programs. Note that extended asm statements must be inside a function.
The P
output modifier is unofficially documented in a comment in gcc/config/i386/i386.md:
;; The special asm out single letter directives following a '%' are:
...
;; P -- if PIC, print an @PLT suffix.
;; p -- print raw symbol name.
The upper-case P
modifier probably isn't what is wanted here, but when not compiling PIC (Position Independent Code), then it acts like the lower-case p
modifier. The intent to prevent the compiler from emitting the operand using the format normally used for immediate values, which wouldn't work here. As David Wohlferd said it would be a better idea to use the c
modifier, which is documented and is meant specifically to handle immediate values. Mind you this code was probably written before the c
modifier was documented, as for a long time none of the modifiers were documented.
Given that the inline assembly statement is only executed once at boot time, performance doesn't matter, so I wouldn't have bothered trying to be smart by using LEA. You can avoid the operand modifiers completely with something simple like:
char *stack_pointer;
asm ("mov %%esp, %0" : "=r" (stack_pointer));
stack_end = stack_pointer - STACK_SIZE;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With