为什么我不能使用 `section .data:` 和 `section .text:` 在 C 中创建一个超过 61 个字符的 char 数组?
Why can't I make a char array longer than 61 characters in C, using `section .data:` and `section .text:`?
我正在按照这个 tutorial 制作一个简单的 32 位操作系统。我已经到了第 4 节,我正在写入帧缓冲区。基本上我正在尝试创建自己的 println 函数。这是我的函数的代码:
/** fb_write_cell:
* Writes a character with the given foreground and background to position i
* in the framebuffer.
*
* @param i The location in the framebuffer
* @param c The character
* @param fg The foreground color
* @param bg The background color
*/
static void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned bg) {
fb[i] = c;
fb[i + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F);
}
/** fb_print:
* Print a string of text to the framebuffer
* @param *buf The character array to print
*/
int fb_print(char *str, unsigned int length) {
unsigned int i = 0, x = 0;
// print the message to the framebuffer
for(; i < (2 * length); i+=2) {
fb_write_cell(i, str[x], FB_BLACK, FB_GREEN);
x++;
}
return 0;
}
/** fb_println:
* Print a string of text to the framebuffer and move to the next line
* @param *buf The character array to print
*/
int fb_println(char *str, unsigned int length) {
fb_print(str, length);
return 0;
}
我这样称呼它:
char array[] = "Hello world!";
fb_println(array, sizeof(array));
但是,如果我使数组长度超过 61 个字符,我将停止向屏幕输出任何内容。事实上,数组创建后的任何代码都不会被执行。我在想这可能与我的裸系统中有限的 RAM 有关(也许只有 64 字节?),但我不确定。
我的多重启动 header 和 loader.s
中调用我的 C 入口点 main
的启动代码是:
global loader ; the entry symbol for ELF
MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant
FLAGS equ 0x0 ; multiboot flags
CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum
; (magic number + checksum + flags should equal 0)
KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes
extern sum_of_three ; the function is defined elsewhere
extern main
section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
dd MAGIC_NUMBER ; write the magic number to the machine code,
dd FLAGS ; the flags,
dd CHECKSUM ; and the checksum
section .bss:
align 4 ; align at 4 bytes
kernel_stack: ; label points to beginning of memory
resb KERNEL_STACK_SIZE ; reserve stack for the kernel
loader: ; the loader label (defined as entry point in linker script)
mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax
mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the
; stack (end of memory area)
;Example of how to call a function and send args
;push dword 3 ; arg3
;push dword 2 ; arg2
;push dword 1 ; arg1
;call sum_of_three ; call the function, the result will be in EAX
.loop:
call main
jmp .loop ; loop forever
我的链接描述文件 link.ld
是:
ENTRY(loader) /* the name of the entry label */
SECTIONS {
. = 0x00100000; /* the code should be loaded at 1 MB */
.text ALIGN (0x1000) : /* align at 4 KB */
{
*(.text) /* all text sections from all files */
}
.rodata ALIGN (0x1000) : /* align at 4 KB */
{
*(.rodata*) /* all read-only data sections from all files */
}
.data ALIGN (0x1000) : /* align at 4 KB */
{
*(.data) /* all data sections from all files */
}
.bss ALIGN (0x1000) : /* align at 4 KB */
{
*(COMMON) /* all COMMON sections from all files */
*(.bss) /* all bss sections from all files */
}
}
可以找到我的全部源代码here。
此处的问题与您的 C 代码无关,而是您的文件 loader.s
中的问题。节名称末尾有一个冒号成为节名称的一部分,并且您没有将代码放在可执行文件 .text
节中,您遇到了问题。
这些行在节名称上有额外的冒号:
section .text: ; start of the text (code) section
section .bss:
它们应该是:
section .text ; start of the text (code) section
section .bss
这些额外的冒号会导致内容以意想不到的方式放置,并且可能会受到特定部分中数据量的影响(例如 C 代码中的字符串)。这可能导致您的 kernel.elf
并不总是显示为多引导兼容的引导加载程序。
代码也需要放在 .text
部分。您将堆栈和代码放在 .bss
部分中,这是不正确的。要解决此问题,请在代码开头上方放置一个部分指令,如下所示:
section .text
loader: ; the loader label (defined as entry point in linker script)
您还将内核置于无限循环中:
.loop:
call main
jmp .loop ; loop forever
您可能打算在内核完成后放置一个无限循环:
call main
.loop:
jmp .loop ; loop forever
LittleOS 书籍教程错误
我注意到这似乎是您在 Compiling the Operating System 部分使用的教程作者的错误,因为错误出现在这段代码中:
section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
有人不妨向作者提出这个问题
我正在按照这个 tutorial 制作一个简单的 32 位操作系统。我已经到了第 4 节,我正在写入帧缓冲区。基本上我正在尝试创建自己的 println 函数。这是我的函数的代码:
/** fb_write_cell:
* Writes a character with the given foreground and background to position i
* in the framebuffer.
*
* @param i The location in the framebuffer
* @param c The character
* @param fg The foreground color
* @param bg The background color
*/
static void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned bg) {
fb[i] = c;
fb[i + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F);
}
/** fb_print:
* Print a string of text to the framebuffer
* @param *buf The character array to print
*/
int fb_print(char *str, unsigned int length) {
unsigned int i = 0, x = 0;
// print the message to the framebuffer
for(; i < (2 * length); i+=2) {
fb_write_cell(i, str[x], FB_BLACK, FB_GREEN);
x++;
}
return 0;
}
/** fb_println:
* Print a string of text to the framebuffer and move to the next line
* @param *buf The character array to print
*/
int fb_println(char *str, unsigned int length) {
fb_print(str, length);
return 0;
}
我这样称呼它:
char array[] = "Hello world!";
fb_println(array, sizeof(array));
但是,如果我使数组长度超过 61 个字符,我将停止向屏幕输出任何内容。事实上,数组创建后的任何代码都不会被执行。我在想这可能与我的裸系统中有限的 RAM 有关(也许只有 64 字节?),但我不确定。
我的多重启动 header 和 loader.s
中调用我的 C 入口点 main
的启动代码是:
global loader ; the entry symbol for ELF
MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant
FLAGS equ 0x0 ; multiboot flags
CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum
; (magic number + checksum + flags should equal 0)
KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes
extern sum_of_three ; the function is defined elsewhere
extern main
section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
dd MAGIC_NUMBER ; write the magic number to the machine code,
dd FLAGS ; the flags,
dd CHECKSUM ; and the checksum
section .bss:
align 4 ; align at 4 bytes
kernel_stack: ; label points to beginning of memory
resb KERNEL_STACK_SIZE ; reserve stack for the kernel
loader: ; the loader label (defined as entry point in linker script)
mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax
mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the
; stack (end of memory area)
;Example of how to call a function and send args
;push dword 3 ; arg3
;push dword 2 ; arg2
;push dword 1 ; arg1
;call sum_of_three ; call the function, the result will be in EAX
.loop:
call main
jmp .loop ; loop forever
我的链接描述文件 link.ld
是:
ENTRY(loader) /* the name of the entry label */
SECTIONS {
. = 0x00100000; /* the code should be loaded at 1 MB */
.text ALIGN (0x1000) : /* align at 4 KB */
{
*(.text) /* all text sections from all files */
}
.rodata ALIGN (0x1000) : /* align at 4 KB */
{
*(.rodata*) /* all read-only data sections from all files */
}
.data ALIGN (0x1000) : /* align at 4 KB */
{
*(.data) /* all data sections from all files */
}
.bss ALIGN (0x1000) : /* align at 4 KB */
{
*(COMMON) /* all COMMON sections from all files */
*(.bss) /* all bss sections from all files */
}
}
可以找到我的全部源代码here。
此处的问题与您的 C 代码无关,而是您的文件 loader.s
中的问题。节名称末尾有一个冒号成为节名称的一部分,并且您没有将代码放在可执行文件 .text
节中,您遇到了问题。
这些行在节名称上有额外的冒号:
section .text: ; start of the text (code) section
section .bss:
它们应该是:
section .text ; start of the text (code) section
section .bss
这些额外的冒号会导致内容以意想不到的方式放置,并且可能会受到特定部分中数据量的影响(例如 C 代码中的字符串)。这可能导致您的 kernel.elf
并不总是显示为多引导兼容的引导加载程序。
代码也需要放在 .text
部分。您将堆栈和代码放在 .bss
部分中,这是不正确的。要解决此问题,请在代码开头上方放置一个部分指令,如下所示:
section .text
loader: ; the loader label (defined as entry point in linker script)
您还将内核置于无限循环中:
.loop:
call main
jmp .loop ; loop forever
您可能打算在内核完成后放置一个无限循环:
call main
.loop:
jmp .loop ; loop forever
LittleOS 书籍教程错误
我注意到这似乎是您在 Compiling the Operating System 部分使用的教程作者的错误,因为错误出现在这段代码中:
section .text: ; start of the text (code) section align 4 ; the code must be 4 byte aligned
有人不妨向作者提出这个问题