gcc - 为什么我不能使用 `section .data:` 和 `section .text:` 在 C 中创建长度超过 61 个字符的 char 数组?

标签 gcc assembly x86 nasm osdev

我正在关注这个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

有人可能希望向作者提出这个问题。

关于gcc - 为什么我不能使用 `section .data:` 和 `section .text:` 在 C 中创建长度超过 61 个字符的 char 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46759903/

相关文章:

c++ - 在 gcc 中使用关键字

c++ - 接受任何类型的 STL 容器并使用其值类型

c++ - 抑制 G++ 3.4.6 中的链接错误

c - 这个函数在汇编中的作用是什么?

c - Spin Loop 在缓存一致性方面的开销

c++ - 将 int32 重新解释为 float

c - Raspberry Pi GCC Makefile 和程序结构

c++ - GNU C 内联汇编中的输入操作数 `"m"(var )` and Output Operand ` "=m"(var)` ?不使用任何指令作为屏障?

将 x86 汇编代码片段转换为 C

c - 优化此C(AVR)代码