I am trying to understand how current macro retrieves struct task_struct of the process.
I am trying to understand for x86 architecture, and after exploring kernel source, struck at the following code:
#include <linux/compiler.h>
#include <asm/percpu.h>
#ifndef __ASSEMBLY__
struct task_struct;
DECLARE_PER_CPU(struct task_struct *, current_task);
static __always_inline struct task_struct *get_current(void)
{
return percpu_read_stable(current_task);
}
#define current get_current()
#endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_CURRENT_H */
Where are the variables declared in DECLARE_PER_CPU stored in memory.
Are they at fixed location or in CPU Registers.
I am still unable to get, how this will give the task_struct pointer
Can anyone explain it. Thanks for your time and patience
from what i understood from the sources that i will mention below, the answers to your questions are such:
the variables are already defined by the DEFINE_PER_CPU macro, and the use of DECLARE_PER_CPU is there to tell the compiler that an external reference is being made.
the section in which current_struct variable is stored depends whether the CONFIG_SMP is defined on 32bit arch's, if its defined it will be at ".data.percpu" section otherwise, it will be at ".data" section.
In 64 bit arch it will always be at ".data.percpu".
the variables which are declared by DECLARE_PER_CPU will be stored on the stack.
let me qoute:
On boot up, an area is allocated by the size of the ".data.percpu" section +
PERCPU_ENOUGH_ROOM times NR_CPUS.
The __per_cpu_offset[] array holds the difference between
the ".data.percpu" section and the location where the data is actually
stored.
__per_cpu_offset[0] holds the difference for the variables
assigned to cpu 0, __per_cpu_offset[1] holds the difference for the
variables to cpu 1, and so on.
so, it depandes on the order of the other declarations of "per cpu" variables
the macro per_cpu_read_stable is used to read the "current_task" per-cpu variable.
https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html
https://lwn.net/Articles/180101
https://elixir.bootlin.com/linux/latest/ident/PER_CPU_BASE_SECTION
Unable to understand how the "current" macro works for x86 architecture
Related
#define NVRAM1_PAGE1_FIRST_ADDRESS 0x1000
extern volatile INT16U NVRAM_content[128] __attribute((nodp, addr(NVRAM1_PAGE1_FIRST_ADDRESS)));
This array surely start address from NVRAM1_PAGE1_FIRST_ADDRESS
but How does this code work?
I mean, I was trying to find 'nodp' meaning but there was no information in code or manual.
I am writing an intel x86 assembly program to compute logarithms using a log table. I call the assembly function in a c program. I don't want to move all the values in the log table to memory every time i call. I'm new to assembly on a non-simulated processor, so I'm not even sure where I'm allowed to store it. 20,000 32-bit integers.
How can I store a "large" amount of data once at the beginning of a c program, so that I can access it in an assembly routine? If i put it in the .data section, is it moved to memory every time i call the actual function?
Edit: this is how i call the function
#include <stdio.h>
extern int doIt(float) asm("doIt");
int main(){
printf("%d\n", doIt(7.0));
printf("%d\n", doIt(4.0));
... //more calls of the sort
}
Not sure if the c code is completely correct. In doIt i need to access the mentioned table repeatedly.
To give it an answer:
#include <stdint.h>
const int32_t table[10]; /* .rodata */
int32_t table[10]; /* .bss */
/*
* However, if you initialize with any (nonzero) values
* it goes to:
*/
int32_t table[10]={
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0xaaaaaaaa
}; /* .data */
const int32_t table[10]={
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0xaaaaaaaa
}; /* .rodata */
About the sections: .data and .rodata are stored in the object file and may not be loaded to RAM unless you need to use them, or anything contained into the same page -maybe you can change this behaviour with a linker script, I don't know-, and .bss section doesn't actually store any data, that is why once you initialize the variable, it moves to .data and gets it's image stored into the object file. Most compilers will ignore initialization to zero because the .bss variables do not have their image stored into the object file, so the loader fills their space to zero anyways when it loads the program.
Then, when you compile the object, you can import the symbol name from your ASM routine.
The Problem
On a personal project of mine, I have a struct defined in a UART abstraction library (let's call it UART.c and UART.h)I made for an AVR.
In UART.h:
typedef struct ST_UARTRX_MESSAGECONTENTS{
uint8_t u_command[3]; //Command
uint32_t u32_value; //Parameter for Command
boolean b_newValue; //Is there new value written here
boolean b_Error; //Is there an error with this message
} ST_UARTRX_MESSAGECONTENTS;
volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;
So basically it's a structure that holds a UART message, it has a "b_newValue" that's a flag for when a new message is received. A message is "received" when the AVR receives a new line "\n".
In the header file of another file (let's call "foo.h"): I include my "UART abstraction library" and put this in the header:
extern volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;
But then in foo.c, I try to access the "b_newValue":
if(st_uartRX_MessageContents.b_newValue){
st_uartRX_MessageContents.b_newValue = TRUE;
fsm_state = ST_STOREMACRO;
}
But the "if" is never entered even if my debugger says the struct value is indeed true:
You can see I have breaked at the if statement. If I hit "Step", it just skips over it and doesn't enter!
Boolean typedef for reference:
typedef enum{FALSE, TRUE} boolean;
Some things I've tried
When I look at the compiled ASM code, I see that general purpose register R24 is used to load the b_newValue, but it loads 0x00, not 0x01 like I'd expect.
uartTX_sendArray(st_uartRX_MessageContents.u_command, sizeof st_uartRX_MessageContents.u_command);
delay_ms(2000);
if(st_uartRX_MessageContents.b_newValue){
st_uartRX_MessageContents.b_newValue = TRUE;
fsm_state = ST_STOREMACRO;
}
I used my "UART: send this array" function to send the ascii "command" from the same structure, and it works! I have no idea why my foo.c can see the "command" but not the "b_newValue".
I've been ripping my hair out for hours. Thanks for looking.
Judging by what you posted now, you have your struct object defined in the header file UART.h
volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;
That's formally illegal (if you include UART.h into multiple translation units) and is generally not a good idea even if some compilers accept it as an extension. I would suggest you move the above definition into a UART.c file and place a non-defining declaration
extern volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;
into UART.h.
I have a question regarding how symbols are placed in the symbol table and then how you reference those symbols from within C.
So let's say I have a startup assembly file where some basic stuff is done before calling main(). One of the things it does is EXPORT a couple symbols which define the stack.
St_Length EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
EXPORT St_Length
EXPORT ra_Stack
ra_Stack SPACE St_Length
Then in a source.c file in which I want to reference those symbols I have something like:
extern uint32_t St_Length; /* exported from asm.s */
void func( void )
{
uint32_t i;
for(i = 0; i < (uint32_t)(&St_Length); ++i)
\\do something
}
This seems to work correctly, i.e. it will actually perform that loop 0x400 times. My question is why do I have to use the ampersand to get what seems to me like it should be the value of the symbol, not the address of the symbol?
NOTE: this is for an ARM Cortex-M3 using the toolchain provided with Keil.
Thanks for the help.
EDIT: Here is the relevant portion of my symbol table from the generated map file:
Global Symbols
Symbol Name Value Ov Type Size Object(Section)
St_Length 0x00000400 Number 0 startup_stm32f10x_md.o ABSOLUTE
Any explanation of the symbol table 'type' column would be very helpful too.
Because using EQU you have defined St_Length as a symbol for address 0x400. To define it as a variable at some appropriate address, you should try something along the lines of:
St_Length DCD 0x400
(Put this in your data area.)
Hi I am trying to create a counter that will just count the number of times the system call vfork() has been called in fork.c in the Linux kernel source. I'am following how total_forks is implemented. Total_forks is defined in sched.h. But I can't find where it is initialized to zero.
I'm guessing you are talking about the Linux kernel, and the variable declared in sched.h and defined here. It's a global variable (defined at file scope and not static) - these are implicitly initialized to zero. Try this in you own code:
#include <stdio.h>
int var;
int main( int argc, char* argv[] ) {
printf( "var is %d\n", var );
return 0;
}
I'm unfamiliar with the source you're looking at, but a few thoughts spring to mind:
It may be initialized to 1 when init is started.
It may be initialized to 0 because it is in the BSS segment; the runtime system knows to initialize a portion of memory for variables and clears it all before giving it to the 'main' kernel process at early boot.