gpt4 book ai didi

assembly - 如果我尝试将 x86-assembly (r)si 中的寄存器指向标签,为什么它会移入自身?

转载 作者:行者123 更新时间:2023-12-05 00:14:24 24 4
gpt4 key购买 nike

我想编写一个引导加载程序,它只打印“Hello World!”在屏幕上,我不知道为什么我的字节会混淆。我正在尝试用 AT&T 语法编写它(请不要推荐 Intel 语法)并尝试转换代码 from this tutorial到 AT&T 语法。

现在这是我的引导加载程序的相当短的代码:

start:
.code16 #real mode
.text
.org 0x0
.globl _main
_main:
movw hello, %si
movb $0x0e, %ah

loophere:
lodsb
or %al, %al #is al==0 ?
jz halt #if previous instruction sets zero flag jump to halt
int $0x10 #run bios interrupt 0x10 (ah is set to 0x0e so a character is displayed)
jmp loophere


halt:
cli
hlt


hello: .ascii "Hello world!\0"


filloop:
.fill (510-(.-_main)),1,0 #I hope this works. Fill bootloader with 0's until byte 510


end:
.word 0xaa55

现在如果我编译这个
$as -o boot.o boot.as
$ld -Ttext 0x07c00 -o boot.elf boot.o
$objcopy -O binary boot.elf boot.bin

以下命令
$objdump -d boot.elf

给我这个反汇编
Disassembly of section .text:

0000000000007c00 <_main>:
7c00: 8b 36 mov (%rsi),%esi
7c02: 11 7c b4 0e adc %edi,0xe(%rsp,%rsi,4)

0000000000007c06 <loophere>:
7c06: ac lods %ds:(%rsi),%al
7c07: 08 c0 or %al,%al
7c09: 74 04 je 7c0f <halt>
7c0b: cd 10 int $0x10
7c0d: eb f7 jmp 7c06 <loophere>

0000000000007c0f <halt>:
7c0f: fa cli
7c10: f4 hlt

0000000000007c11 <hello>:
7c11: 48 rex.W
7c12: 65 6c gs insb (%dx),%es:(%rdi)
7c14: 6c insb (%dx),%es:(%rdi)
7c15: 6f outsl %ds:(%rsi),(%dx)
7c16: 20 77 6f and %dh,0x6f(%rdi)
7c19: 72 6c jb 7c87 <filloop+0x69>
7c1b: 64 21 00 and %eax,%fs:(%rax)

0000000000007c1e <filloop>:
...

0000000000007dfe <end>:
7dfe: 55 push %rbp
7dff: aa stos %al,%es:(%rdi)

如果我 hexdump 它(你也可以在上面的反汇编中看到字节)我的前 6 个字节是
8b 36
11 7c b4 0e

be 10 7c b4 0e 相比来自教程(十六进制转储的其余部分与字节完全相同)。现在我明白了 ac是 lodsb (loadstringbyte) 的指令所以 b4 0e必须加载 0e进入 %ahbe 10 7c就得点 %si到地址 7c10 处的 hello 标签(注意小端)。我用十六进制编辑器更改了相应的字节,它突然起作用了。尽管拆卸有点像这样混淆:
0000000000007c00 <_main>:
7c00: be 10 7c b4 0e mov $0xeb47c10,%esi
7c05: ac lods %ds:(%rsi),%al

我的原始版本只是打印了一个大写的“S”。有人可以帮助我解释为什么这些第一个指令字节的设置不同吗?

我在 Debian 9 64 位上编写了所有这些代码,并将它作为软盘在 qemu-system-x86_64 上运行。

最佳答案

如果你想将指令解码为 16 位,那么你需要用 -Mi8086 告诉 OBJDUMP选项。由于您使用 AS 和 LD 创建了 64 位对象,因此默认情况下它解码为 64 位指令。 -M覆盖那个。 i8086 是 16 位指令解码。

您代码中的许多问题都与没有正确设置段寄存器(包括 DS)有关。我在 Bootloader Tips 中讨论了许多这些问题。 .在 AT&T 语法中也需要 $如果您想要它们的地址(立即操作数),请放在标签前面。 movw hello, %si应该是 movw $hello, %si .或者,您可以使用采用内存操作数并仅计算地址(但不检索数据)的 LEA。在这种情况下,您不使用 $标志。 leaw hello, %si也应该工作。

使用时 INT 10h/AH=0Eh您应该设置 BH,这是要显示的页码。 0 是可见页面。

考虑到所有这些,这段代码应该可以工作:

start:
.code16 #real mode
.text
.globl _main
_main:
xor %ax, %ax # We are usin offset 0x7c00, thus we need to se segment to 0x0000
mov %ax, %ds
mov %ax, %es
mov %ax, %ss # Set the stack to grow down just below bootloader
mov $0x7c00, %sp
cld # Ensure forward movement of lods/movs/scas instructions

movw $hello, %si # We want the address of hello, not what it points at
#leaw hello, %si # Alternative way to get address with LEA instruction.
movb $0x0e, %ah
xor %bh, %bh # Make sure video page number is set (we want 0)

loophere:
lodsb
or %al, %al #is al==0 ?
jz halt #if previous instruction sets zero flag jump to halt
int $0x10 #run bios interrupt 0x10 (ah is set to 0x0e so a character is displayed)
jmp loophere


halt:
cli
hlt


hello: .ascii "Hello world!\0"


filloop:
.fill (510-(.-_main)),1,0 #I hope this works. Fill bootloader with 0's until byte 510


end:
.word 0xaa55

关于assembly - 如果我尝试将 x86-assembly (r)si 中的寄存器指向标签,为什么它会移入自身?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46955403/

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