gpt4 book ai didi

assembly - 使用 GAS AT&T 指令为引导扇区计算填充长度?

转载 作者:行者123 更新时间:2023-12-03 15:10:48 33 4
gpt4 key购买 nike

所以我想在引导扇区中添加填充。比方说,目前只有一个无限循环:jmp . .该扇区的长度需要为 512 字节。此外,魔术号码 0xaa55需要在最后添加。

jmp .
.skip 508, 0
.word 0xaa55

但是如果我想打印一些东西但不想计算所有字节以将其填充到正确的大小怎么办?
在 Intel/NASM 语法中,它是:
; print something
times 510-($-$$) db 0
dw 0xaa55

但是在 AT&T 语法中?那么循环( .rept )在这里不起作用,因为 .没有给出这里需要的绝对值。我们对 .skip 也有同样的问题/ .space ,它们也需要一个绝对值。

有没有一种方法可以使用某种循环/ .align 添加填充/ .skip/等等?

编辑:
我用 as构建和链接 ld -Ttext 0x7c00 --oformat binary直到 yasm对于 AT&T 语法来说足够稳定。

最佳答案

使用 AT&T 语法,您可以在引导加载程序的开头放置一个标签,然后使用以下内容:

.global _start
.text
.code16
_start:
jmp .

.space 510-(.-_start)
.word 0xaa55

期间 .是相对于当前部分开头的当前位置计数器。期间的区别 ._start是一个绝对值,所以应该在这个表达式中工作。

您可以使用 GCC(将调用 LD)使用如下命令将其组装到引导加载程序中:
gcc -Wl,--oformat=binary -Wl,-Ttext=0x7c00 -Wl,--build-id=none \
-nostartfiles -nostdlib -m32 -o boot.bin boot.s

选项 -Wl,--oformat=binary将此选项传递给链接器,这将强制它输出到平面二进制文件。 -Wl,-Ttext=0x7c00将此选项传递给链接器,链接器将有效地将原点设置为 0x07c00。 -Wl,--build-id=none告诉链接器不要使用 GCC 可能生成的构建 ID。 0x7c00 是代码预期加载的偏移量。由于我们不能使用标准库或 C 运行时,我们用 -nostartfiles -nostdlib 排除它们。

如果您打算将多个文件链接在一起,您将无法使用此方法。在这种情况下,您需要将引导签名从代码中删除,并让链接器使用特制的链接器脚本来处理它。如果您将引导加载程序包含到单个程序集文件中,则上述方法将起作用。

我有一些通用的 bootloader tips用于编写引导加载程序代码。人们通常遇到的一个大问题是没有设置段寄存器。如果您使用 0x7c00 的原点,那么您至少需要确保 DS register us 设置为 0。如果您编写的代码使用引用代码中标签的内存操作数,这将很重要。

使用 GNU 汇编器进行汇编时,请确保设置了所需的正确指令编码。 .code16将使汇编程序假定目标处理器在 16 位模式下运行。 .code32对于 32 位编码, .code64假设 64 位编码。 as 的默认值一般从不 .code16 .

具有多个目标文件的引导加载程序

正如我上面提到的,使用多个目标文件来创建引导加载程序带来了汇编指令无法克服的挑战。为此,您可以创建一个特殊的链接器脚本,将 Origin 点设置为 0x7c00,并让链接器将引导签名放置在输出文件中。使用这种方法你不需要做任何填充,链接器会为你做。处理传统部分的基本链接描述文件,如 .text , .data , .rodata如下所示。您可能永远不会使用某些部分,但我添加了它们作为示例:

文件 bootloader.ld
OUTPUT_FORMAT("elf32-i386");
ENTRY(_start);
SECTIONS
{
. = 0x7C00;
/* Code section, .text.bootentry code before other code */
.text : SUBALIGN(0) {
*(.text.bootentry);
*(.text)
}

/* Read only data section with no alignment */
.rodata : SUBALIGN(0) {
*(.rodata)
}

/* Data section with no alignment */
.data : SUBALIGN(0) {
*(.data)
}

/* Boot signature at 510th byte from 0x7c00 */
.sig : AT(0x7DFE) {
SHORT(0xaa55);
}

/DISCARD/ : {
*(.eh_frame);
*(.comment);
*(.note*);
}
}

文件 boot.s包含引导加载程序的主要入口点:
# Section .text.bootentry is always placed before all other code and data
# in the linker script. If using multiple object files only specify
# one .text.bootentry as that will be the code that will start executing
# at 0x7c00

.section .text.bootentry
.code16
.global _start
_start:
# Initialize the segments especially DS and set the stack to grow down from
# start of bootloader at _start. SS:SP=0x0000:0x7c00
xor %ax, %ax
mov %ax, %ds
mov %ax, %ss
mov $_start, %sp
cld # Set direction flag forward for string instructions

mov $0x20, %al # 1st param: Attribute black on green
xor %cx, %cx # 2nd param: Screen cell index to write to. (0, 0) = upper left
mov $boot_msg, %dx # 3rd param: String pointer
call print_str

# Infinite loop to end bootloader
cli
.endloop:
hlt
jmp .endloop

.section .rodata
boot_msg: .asciz "My bootloader is running"

文件 aux.s使用一个简单的函数将字符串直接显示到屏幕上:
.global print_str         # Make this available to other modules
.section .text
.code16

# print_str (uint8_t attribute, char *str, uint16_t cellindex)
#
# Print a NUL terminated string directly to video memory at specified screen cell
# using a specified attribute (foreground/background)
#
# Calling convention:
# Watcom
# Inputs:
# AL = Attribute of characters to print
# CX = Pointer to NUL terminated string to print
# DX = Screen cell index to start printing at (cells are 2 bytes wide)
# Clobbers:
# AX, ES
# Returns:
# Nothing

print_str:
push %di
push %si

mov $0xb800, %di # Segment b800 = text video memory
mov %di, %es
mov %cx, %di # DI = screen cell index (0 = upper left corner)
mov %dx, %si # SI = pointer to string (2nd parameter)
mov %al, %ah # AH = attribute (3rd parameter)
jmp .testchar

# Print each character until NUL terminator found
.nextchar:
stosw # Store current attrib(AH) and char(AL) to screen
# Advances DI by 2. Each text mode cell is 2 bytes
.testchar:
lodsb # Load current char from string into AL(advances SI by 1)
test %al, %al
jne .nextchar # If we haven't reach NUL terminator display character
# and advance to the next one

pop %si
pop %di
ret

将此引导加载程序构建到名为 boot.bin 的文件中我们可以这样做:
as --32 aux.s -o aux.o
as --32 boot.s -o boot.o
ld -melf_i386 --oformat=binary -Tlink.ld -nostartfiles -nostdlib \
aux.o boot.o -o boot.bin

特价 .text.bootentry被链接描述文件放置为第一个代码。此部分应仅在一个目标文件中定义,因为它将是出现在引导加载程序开头 0x7c00 处的代码。链接描述文件将 VMA(原点)调整为 0x7dfe 并写入引导签名(0xaa55)。 0x7dfe 比前 512 个字节的结尾低 2 个字节。我们不再在汇编代码中进行任何填充,也不在那里发出引导签名。

运行此示例引导加载程序时,应在显示屏的左上角打印一个字符串,在绿色背景上显示黑色。

关于assembly - 使用 GAS AT&T 指令为引导扇区计算填充长度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47859273/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com