我使用 GNU 汇编器和 AT&T 语法编写了我的第一个引导加载程序。它应该打印hello world到屏幕上,然后通知用户按任意键将导致重新启动。只有按下某个键后才会启动重新启动。我的引导加载程序代码不等待按键,并在打印信息后自动重新启动。为什么此代码不等待击键,我该如何修复它?
我的引导扇区代码:
#generate 16-bit code
.code16
#hint the assembler that here is the executable code located
.text
.globl _start;
#boot code entry
_start:
jmp _boot #jump to boot code
welcome: .asciz "Hello, World\n\r" #here we define the string
AnyKey: .asciz "Press any key to reboot...\n\r"
.macro mWriteString str #macro which calls a function to print a string
leaw \str, %si
call .writeStringIn
.endm
#function to print the string
.writeStringIn:
lodsb
orb %al, %al …Run Code Online (Sandbox Code Playgroud) 所以我遇到了一个问题,让我质疑我对DB(define byte) 和DUP(duplicate) 指令的基本理解。我对它们的理解方式是:
NUM DB 34将创建一个名为NUM的变量,并为其分配值 34。类似于 C char NUM = 34;1NUM DB 34 DUP(?)会给我一个包含 34 个项目的数组,每个项目都未分配。 NUM DB 3 DUP(4)会给我一个名为NUM的数组,其中包含 3 个项目:4、4、4。它是否正确?
在我的教科书中我遇到过:
Run Code Online (Sandbox Code Playgroud)PRINT_SELECT DB 133 (?) DB 123 (?)
这只是教科书上的一个错误,还是这两行代码完全有其他含义?
脚注 1:(编者注):NUM = 34在 asm 中定义了一个不存储在数据存储器中的汇编时常量。在 MASM 语法汇编器中,它的工作方式与某些上下文中的变量类似。但例如mul NUM仅适用于内存源,不适用于立即数, whileimul eax, ecx, NUM或 ,shl ax, NUM或mov ax, NUM / 2仅适用于立即数,不适用于内存源。
我试图在汇编中创建一个完整的随机数,但每次启动程序时,它都会以相同的顺序给出相同的数字。如果数字是 12、132、4113 等,每次我启动代码时它都会重复它们。
我试图制作的程序有点像猜谜游戏。
IDEAL
MODEL small
STACK 100h
DATASEG
;vars here
RNG_Seed dw ?
CODESEG
; Generates a pseudo-random 15-bit number.
; Parameters: <none>
; Clobbers: AX, DX
; Returns: AX contains the random number
proc GenerateRandNum
push bx
push cx
push si
push di
; 32-bit multiplication in 16-bit mode (DX:AX * CX:BX == SI:DI)
mov ax, [RNG_Seed]
xor dx, dx
mov cx, 041C6h
mov bx, 04E6Dh
xor di, di
push ax
mul bx
mov si, dx
xchg …Run Code Online (Sandbox Code Playgroud) 下一个程序中的输入工作正常,但是当我要求显示输出时,DOS 根本不显示任何内容!这怎么可能?
ORG 256
mov dx, msg1
mov ah, 09h ;DOS.WriteString
int 21h
mov dx, buf
mov ah, 0Ah ;DOS.BufferedInput
int 21h
mov dx, msg2
mov ah, 09h ;DOS.WriteString
int 21h
mov dx, buf
mov ah, 09h ;DOS.WriteString
int 21h
mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
msg1: db 'Input : ', '$'
buf: db 20 dup ('$')
msg2: db 13, 10, 'Output : ', '$'
; --------------------------------------
Run Code Online (Sandbox Code Playgroud) 谁能帮我解释一下为什么在这些情况下余数的符号不同?这是模拟器错误还是真实的 CPU 也会这样做?
8 / -3 : quotient(AL) = -2 remainder(AH) = 2
-8 / 3 : quotient(AL) = -2 remainder(AH) = -2
Run Code Online (Sandbox Code Playgroud) 我目前正在关注操作系统开发教程,其中包括有关引导加载程序的讨论。
我的引导加载程序当前处于 16 位实模式,因此,我能够使用提供的 BIOS 中断(例如 VGA 视频中断等)。
BIOS 提供视频中断0x10(即视频电传输出)。视频中断具有功能0x0E,它允许我将字符打印到屏幕上。
这是这个基本的引导加载程序:
org 0x7c00 ; Set program start (origin) address location at 0x7c00.
; This program is loaded by the BIOS at 0x7c00.
bits 16 ; We live in 16-bit Real Mode.
start:
jmp loader
bootmsg db "Welcome to my Operating System!", 0 ; My data string.
;-------------------------------------------------------
; Description: Print a null terminating string
;-------------------------------------------------------
print:
lodsb ; Load string byte at address DS:SI …Run Code Online (Sandbox Code Playgroud) 我有一个 .ASM 文件,我想在其中调用另一个 .ASM 或 .INC 文件中的过程。
我尝试将以下内容写入我的main.asm文件中:
INCLUDE file_op.inc
Run Code Online (Sandbox Code Playgroud)
然而,当我尝试运行它时,它只是说:
“模拟器已停止。”
当它第一次遇到另一个文件中指定的过程时,它会执行此操作。
另一个 .INC 文件中的过程是:
; A function to open a file using its name and remember its file_handle
open_file proc
mov ax, 3d00h ; System call to open a file
lea dx, file_name ; name of the file we are opening
int 21h ; system interrupt
mov file_handle, ax ; remember file_handle!!
ret
endp
; A function to read from a file byte by byte using …Run Code Online (Sandbox Code Playgroud) 假设我想将堆栈初始化为S字节大小。
我想选择堆栈的基本位置,B以便随着堆栈从 向下增长B,我最终不会覆盖引导加载程序或 BIOS 使用的任何代码或其他内存。
由于我自己编写引导加载程序(并且初始 MBR 扇区被加载到线性地址0x7c00),防止与引导加载程序发生冲突似乎是一个仔细规划的问题。
我如何知道 BIOS 代码所在的位置,以及我的堆栈是否可能覆盖 BIOS 正在使用的任何内存?
另外,是否可以保证初始ss:sp值指向哪里,以及在不设置新值的情况下可以安全使用多少堆栈空间?
这个问题的灵感来自另一个论坛上某人提出的问题。在以下代码中,扩展内联程序集约束Rah和Ral含义是什么。我以前没见过这些:
#include<stdint.h>
void tty_write_char(uint8_t inchar, uint8_t page_num, uint8_t fg_color)
{
asm (
"int $0x10"
:
: "b" ((uint16_t)page_num<<8 | fg_color),
"Rah"((uint8_t)0x0e), "Ral"(inchar));
}
void tty_write_string(const char *string, uint8_t page_num, uint8_t fg_color)
{
while (*string)
tty_write_char(*string++, page_num, fg_color);
}
/* Use the BIOS to print the first command line argument to the console */
int main(int argc, char *argv[])
{
if (argc > 1)
tty_write_string(argv[1], 0, 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
特别是在这段代码中使用Rah和Ral作为约束:
asm ( …Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个引导加载程序和一个非常原始和基本的内核,以了解裸机编码实践和技术。无论如何,我正在使用 NASM 编写我的引导程序。我的代码正在运行,但我对要使用的调用约定有疑问。
我只是通过运行 NASM 来编译我的引导加载程序: nasm bootloader.asm -o bootloader。
在我的汇编代码,我写的功能,如BlDisplayString通过BIOS中断显示字符串int 0x10用AH = 0x13。我试图__fastcall通过在CX, DX, STACK. 这是在 16 位代码中使用的正确调用约定标准吗?当我调用这些函数时,CPU 未处于保护模式并且仍处于实模式。
assembly operating-system calling-convention bootloader x86-16