如何在汇编中的FFFF0H位置写入?

时间:2016-12-25 11:16:48

标签: assembly x86-16

我想在 FFFF0H 位置写一条jmp指令,目的地 F8000H

之后,我想将下面的代码放在 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

1 个答案:

答案 0 :(得分:3)

注意

地址范围 0F0000h - 0FFFFFh 是只读的。
真实的故事是,在BIOS的卷影复制完成后,它在启动时被固件设置为只读,因此访问不必一直向下到PCH,默认情况下在标准地址范围 FFFF_0000H - FFFF_FFFFH 重新路由它。

因此,这些地址范围要么映射到只读DRAM区域,要么映射到忽略写入请求直到编程的闪存ROM。

如果您正在编写固件,那么构建链肯定支持创建可放置在ROM中任何位置的部分。
解释如何使用此类工具超出了本答案和本网站的范围。

看来你正在写一个普通的DOS可执行文件,请注意下面的解决方案工作。
因此,我将简单地假设您要将一段代码从 A 移动到 B

我们需要:

  1. 一些代码用于在两个内存区域之间移动数据 这可以通过多种方式完成,最快的代码,但最慢的(对于小块)是使用rep movsbcx字节从ds:si复制到es:di

  2. 一种判断一段代码长度的方法。
    我们可以在代码片段的开头和结尾分别放两个标签,分别是 S E 。这样,表达式 E - S 给出了两个标签之间的差异,以字节为单位,即代码的长度。

  3. 这是一种可能的实施方式:

    .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
    

    正如我所说,除非您在特殊情况下工作,否则此解决方案不会适用于您选择的地址范围。 我还假设你知道细分是如何运作的。

    我没有直接创建远jmp,而是将机器代码存储为mov - 直接存储;相反,我让汇编程序创建机器代码,然后我复制它 它的效率较低,但可以让您轻松更改代码。