determining the kernel size
determining the kernel size
Hello,
I've been told at #osdev (at FreeNode) that it's possible to put a symbol at the end of the linker script and at the start, and then subtracting those to get the size of the kernel.
My questions are:
1. How can I do that?
2. How can I use that symbol from the linker script in C code?
Thanks in advance
I've been told at #osdev (at FreeNode) that it's possible to put a symbol at the end of the linker script and at the start, and then subtracting those to get the size of the kernel.
My questions are:
1. How can I do that?
2. How can I use that symbol from the linker script in C code?
Thanks in advance
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
1:
You can define symbols anywhere in your linker script. There is an example here
2:
You can import the symbol by using and then use it wherever you want.
You can define symbols anywhere in your linker script. There is an example here
2:
You can import the symbol by using
Code: Select all
extern int symbol_name;
So by modifying the example, would this be a correct way to determine the kernel size?
Code: Select all
ENTRY (_loader)
SECTIONS{
kernel_start = .;
. = 0x00100000;
.text :{
*(.text)
}
.rodata ALIGN (0x1000) : {
*(.rodata)
}
.data ALIGN (0x1000) : {
*(.data)
}
.bss : {
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
kernel_size = . - kernel_start;
}
Hmm why do I need to use a "&" in front of my variable name in my C code like below? If I'd let it out, it tries to dereference the symbol.
Oh and how could I get the size of the kernel exactly? I mean when I put the symbol "kernel_size" in the linker script after the BSS section, I get the size of the kernel in memory (which actually is what I wanted), not on disk. But when I put the "kernel_size" symbol before the BSS section, I don't get the correct file size either.
Code: Select all
extern unsigned long kernel_size;
kprintf("Kernel size: 0x%x\n", &kernel_size);
Why would that make a difference?
Anyways, it _does_ make a difference. By subtracting it inside the linker script I measured a kernel size of 0x8000 bytes, and by doing it inside the code I measured a kernel size of 0x2000 bytes.
In code, it subtracts the addresses of the symbols, and in the linker script it subtracts the virtual address assigned to the symbol, is this what happens?
Anyways, it _does_ make a difference. By subtracting it inside the linker script I measured a kernel size of 0x8000 bytes, and by doing it inside the code I measured a kernel size of 0x2000 bytes.
In code, it subtracts the addresses of the symbols, and in the linker script it subtracts the virtual address assigned to the symbol, is this what happens?
As far as my limited knowledge of linker scripts goes, I believe you are correct. The linker script is aligning the positions of the variables to your script.
Try something like this in C if you already haven't
Other than that, try "end - (put base address here, i.e 0x00100000")"
Hope that helps,
--Michael
Try something like this in C if you already haven't
Code: Select all
extern long start;
extern long end;
long size = end - start;
Hope that helps,
--Michael
I now have this C code:
The linker script I now have is an attachment, please check it too.
This code gives the following output:
Kernel start: 0xc0100000
Kernel end: 0xc0108000
Kernel size: 0x2000
Maybe it's my knowledge of C, but I can't really understand why the result of the subtraction is 0x2000 instead of 0x8000.
EDIT: Good news:
When doing it like this:
uintptr_t end = (uintptr_t)&kernel_end;
uintptr_t start = (uintptr_t)&kernel_start;
uintptr_t size = end-start;
It works! But why? Why do I first need to assign new variables the value, and then subtract those?
Code: Select all
/* <TODO> display the size of the kernel */
extern unsigned long kernel_end;
extern unsigned long kernel_start;
kprintf("Kernel start: 0x%x\n", &kernel_start);
kprintf("Kernel end: 0x%x\n", &kernel_end);
kprintf("Kernel size: 0x%x bytes\n", (&kernel_end - &kernel_start));
This code gives the following output:
Kernel start: 0xc0100000
Kernel end: 0xc0108000
Kernel size: 0x2000
Maybe it's my knowledge of C, but I can't really understand why the result of the subtraction is 0x2000 instead of 0x8000.
EDIT: Good news:
When doing it like this:
uintptr_t end = (uintptr_t)&kernel_end;
uintptr_t start = (uintptr_t)&kernel_start;
uintptr_t size = end-start;
It works! But why? Why do I first need to assign new variables the value, and then subtract those?
- Attachments
-
- kernel.ld
- Linker script
- (501 Bytes) Downloaded 145 times
- AndrewAPrice
- Member
- Posts: 2309
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
A more difficult way:
Place everything into one huge C++ class. Then call sizeof(kernel_class);
Place everything into one huge C++ class. Then call sizeof(kernel_class);
My OS is Perception.
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
- carbonBased
- Member
- Posts: 382
- Joined: Sat Nov 20, 2004 12:00 am
- Location: Wellesley, Ontario, Canada
- Contact:
Since your first question wasn't directly addressed (although has probably been discovered already) -- it's because the linker script merely defines symbols (and not variables with values, as is often thought). They have no size. By taking the value of a linker symbol, you're actually getting the bytes after the location of the symbol.bughunter wrote:Hmm why do I need to use a "&" in front of my variable name in my C code like below? If I'd let it out, it tries to dereference the symbol.
However, since it's a located symbol, taking the address of the symbol yields the value you're looking for.
--Jeff