我如何在汇编中的 FFFF0H 位置写入?
How I can write at a location FFFF0H in assembly?
我想在位置 FFFF0H 和目标 F8000H.
处写入一条 jmp
指令
之后,我想把下面的代码放在F8000H,这样在从FFFF0H执行时,控制权就会转移,通过上面的跳转,就可以了。
.MODEL SMALL
.8086
.STACK
.DATA
.CODE
.STARTUP
LL:
MOV AL, 1H
IO_LOOP:
OUT 0EH, AL
SHL AL, 1
;Delay
MOV CX, 0FFFFH
DLOOP:
NOP
LOOP DLOOP
;Start all over again
CMP AL, 00H
JE LL
;Get back to IO cycle
JMP IO_LOOP
END
备注
地址范围0F0000h-0FFFFFh是只读的。
真实的故事是,在创建 BIOS 的影子副本后,它在启动时被固件设置为只读,因此访问不必一直向下到 PCH,默认情况下重新路由它在标准地址范围 FFFF_0000H-FFFF_FFFFH。
因此,这些地址范围要么映射到只读 DRAM 区域,要么映射到闪存 ROM,后者会在编程之前忽略写入请求。
如果您正在编写固件,那么构建链肯定支持创建可以放置在 ROM 中任何位置的部分。
解释如何使用此类工具超出了本答案和本网站的范围。
虽然您正在编写一个普通的 DOS 可执行文件,但请注意下面的解决方案不会工作。
因此,我将简单地假设您想要将一段代码从 A 移动到 B。
我们需要:
在两个内存区域之间移动数据的一些代码。
这可以通过多种方式完成,编码最快,但最慢(对于小块)是使用 rep movsb
将 cx
字节从 ds:si
复制到 es:di
。
一种判断一段代码长度的方法。
我们可以在代码段的开头和结尾分别放置两个标签,比如 S 和 E。这样,表达式 E-S 给出了两个标签之间的差异(以字节为单位),即代码的长度。
这里是一个可能的实现:
.MODEL SMALL
.8086
.STACK
.DATA
.CODE
.STARTUP
;Set up ES
mov ax, 0f000h
mov es, ax
;Move the first routine
mov si, OFFSET __ROUTINE_1__START__ ;DS:SI = Start of the routine to copy
mov di, 8000h ;ES:DI = 0f000h:8000h = 0f8000h
mov cx, __ROUTINE_1__END__ - __ROUTINE_1__START__ ;CX = Length of the routine to copy
rep movsb
;Copy the jump
mov si, OFFSET __ROUTINE_2__START__
mov di, 0fff0h ;ES:DI = 0f000h:0fff0h = 0ffff0h
mov cx, 5 ;Absolute far jump is 5 bytes
rep movsb
;DO SOMETHING HERE
;
; ROUTINE TO MOVE
;
__ROUTINE_1__START__:
LL:
MOV AL, 1H
IO_LOOP:
OUT 0EH, AL
SHL AL, 1
;Delay
MOV CX, 0FFFFH
DLOOP:
NOP
LOOP DLOOP
;Start all over again
CMP AL, 00H
JE LL
;Get back to IO cycle
JMP IO_LOOP
__ROUTINE_1__END__:
__ROUTINE_2__START__:
jmp FAR 0f000h:8000h ;TODO: Adjust the syntax for the assembler dialect
END
如我所说,此解决方案不适用于您选择的地址范围,除非您在特殊环境中工作。
我还假设您知道分段的工作原理。
我并没有直接通过 mov
-immediate 存储机器码来创建 far jmp
;相反,我让汇编程序创建机器代码,然后复制它。
它的效率较低,但可以让您轻松更改代码。
我想在位置 FFFF0H 和目标 F8000H.
处写入一条jmp
指令
之后,我想把下面的代码放在F8000H,这样在从FFFF0H执行时,控制权就会转移,通过上面的跳转,就可以了。
.MODEL SMALL
.8086
.STACK
.DATA
.CODE
.STARTUP
LL:
MOV AL, 1H
IO_LOOP:
OUT 0EH, AL
SHL AL, 1
;Delay
MOV CX, 0FFFFH
DLOOP:
NOP
LOOP DLOOP
;Start all over again
CMP AL, 00H
JE LL
;Get back to IO cycle
JMP IO_LOOP
END
备注
地址范围0F0000h-0FFFFFh是只读的。
真实的故事是,在创建 BIOS 的影子副本后,它在启动时被固件设置为只读,因此访问不必一直向下到 PCH,默认情况下重新路由它在标准地址范围 FFFF_0000H-FFFF_FFFFH。
因此,这些地址范围要么映射到只读 DRAM 区域,要么映射到闪存 ROM,后者会在编程之前忽略写入请求。
如果您正在编写固件,那么构建链肯定支持创建可以放置在 ROM 中任何位置的部分。
解释如何使用此类工具超出了本答案和本网站的范围。
虽然您正在编写一个普通的 DOS 可执行文件,但请注意下面的解决方案不会工作。
因此,我将简单地假设您想要将一段代码从 A 移动到 B。
我们需要:
在两个内存区域之间移动数据的一些代码。
这可以通过多种方式完成,编码最快,但最慢(对于小块)是使用rep movsb
将cx
字节从ds:si
复制到es:di
。一种判断一段代码长度的方法。
我们可以在代码段的开头和结尾分别放置两个标签,比如 S 和 E。这样,表达式 E-S 给出了两个标签之间的差异(以字节为单位),即代码的长度。
这里是一个可能的实现:
.MODEL SMALL
.8086
.STACK
.DATA
.CODE
.STARTUP
;Set up ES
mov ax, 0f000h
mov es, ax
;Move the first routine
mov si, OFFSET __ROUTINE_1__START__ ;DS:SI = Start of the routine to copy
mov di, 8000h ;ES:DI = 0f000h:8000h = 0f8000h
mov cx, __ROUTINE_1__END__ - __ROUTINE_1__START__ ;CX = Length of the routine to copy
rep movsb
;Copy the jump
mov si, OFFSET __ROUTINE_2__START__
mov di, 0fff0h ;ES:DI = 0f000h:0fff0h = 0ffff0h
mov cx, 5 ;Absolute far jump is 5 bytes
rep movsb
;DO SOMETHING HERE
;
; ROUTINE TO MOVE
;
__ROUTINE_1__START__:
LL:
MOV AL, 1H
IO_LOOP:
OUT 0EH, AL
SHL AL, 1
;Delay
MOV CX, 0FFFFH
DLOOP:
NOP
LOOP DLOOP
;Start all over again
CMP AL, 00H
JE LL
;Get back to IO cycle
JMP IO_LOOP
__ROUTINE_1__END__:
__ROUTINE_2__START__:
jmp FAR 0f000h:8000h ;TODO: Adjust the syntax for the assembler dialect
END
如我所说,此解决方案不适用于您选择的地址范围,除非您在特殊环境中工作。 我还假设您知道分段的工作原理。
我并没有直接通过 mov
-immediate 存储机器码来创建 far jmp
;相反,我让汇编程序创建机器代码,然后复制它。
它的效率较低,但可以让您轻松更改代码。