- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在保护模式下调用内存地址低于当前函数的函数时,我遇到异常。异常会根据代码配置而有所不同,有时是一般保护故障,有时是无效的操作码等。
这里是一个程序的源代码,该程序在硬件上产生一般保护错误,在 DOSBox 中产生双重错误。相关代码位于段seg32
中。当func1
尝试回调func2
single segment stack
assume cs:single,ds:single,ss:single
gdesc struc ;global descriptor structure definition
limit_lo dw 0ffffh ;low word of 20-bit limit (bits 15:0)
base_lo dw ? ;low word of base address (bits 15:0)
base_mid db ? ;middle byte of base address (bits 23:16)
priv db ? ;privilege and type bits
limit_hi db ? ;granularity, operand size, hi nybble of limit (bits 19:16)
base_hi db ? ;high byte of base address (bits 31:24)
gdesc ends
idesc struc ;interrupt descriptor structure definition
offset_lo dw ? ;low word of offset
selector dw ? ;selector in gdt
unused db 0 ;always zero
type_attr db ? ;type attribute bits
offset_hi dw ? ;high word of offset
idesc ends
;global descriptor table, phys addresses calculated by init code
nulld gdesc <0,0,0,0,0,0> ;null descriptor
pcode gdesc <,,,09eh,0cfh,> ;protected mode code descriptor
pdata gdesc <,,,092h,0cfh,> ;protected mode data descriptor
rcode gdesc <,,,09ah,08fh,> ;real mode code descriptor
rdata gdesc <,,,092h,08fh,> ;real mode data descriptor
vbuff gdesc <,0,0ah,092h,0cfh,> ;vga pixel buffer data descriptor
tbuff gdesc <,8000h,0bh,092h,0cfh,> ;text buffer data descriptor
gdt_limit dw offset gdt_limit-offset nulld-1 ;gdt_limit <- gdt size in bytes-1
gdt_addr dd offset nulld ;gdt_addr <- offset of gdt, physical address calculated at runtime
idt_div idesc <div_err-offset_0,8,0,0eeh,0> ;interrupt descriptor table, div error
idesc <dont_care-offset_0,8,0,0eeh,0> ;debugger call
idesc <nmi-offset_0,8,0,0eeh,0> ;nmi interrupt
idesc <dont_care-offset_0,8,0,0eeh,0> ;breakpoint
idesc <dont_care-offset_0,8,0,0eeh,0> ;into overflow
idesc <dont_care-offset_0,8,0,0eeh,0> ;bound overflow
idesc <invalid_op-offset_0,8,0,0eeh,0> ;invalid opcode
idesc <fpu_err-offset_0,8,0,0eeh,0> ;coprocessor unavailable
idesc <double_fault-offset_0,8,0,0eeh,0> ;double fault
idesc <fpu_err-offset_0,8,0,0eeh,0> ;coprocessor overrun
idesc <dont_care-offset_0,8,0,0eeh,0> ;invalid tss
idesc <not_present-offset_0,8,0,0eeh,0> ;segment not present
idesc <dont_care-offset_0,8,0,0eeh,0> ;stack exception
idesc <gp_fault-offset_0,8,0,0eeh,0> ;general protection fault
idesc <dont_care-offset_0,8,0,0eeh,0> ;reserved
idesc <fpu_err-offset_0,8,0,0eeh,0> ;coprocessor error
idesc 16 dup (<dont_care-offset_0,8,0,0eeh,0>) ;16 reserved
idt_pit idesc <pit_isr-offset_0,8,0,0eeh,0> ;timer isr
idt_kbd idesc <kbd_isr-offset_0,8,0,0eeh,0> ;keyboard isr
idt_limit dw offset idt_limit-offset idt_div-1 ;idt_limit <- idt size in bytes-1
idt_addr dd offset idt_div ;idt_addr <- offset of idt, complete physical address
;calculated at runtime
ridt_limit dw 3ffh ;real mode idt limit
ridt_addr dd 0 ;real mode idt address
m_pic_mask db ? ;original master pic mask
s_pic_mask db ? ;original slave pic mask
start:
mov ax, cs
mov ds, ax ;ds = cs, single segment
cli ;disable maskable interrupts
in al, 70h ;al <- cmos ram index register port
or al, 80h ;set bit 7 to disable nmi
out 70h, al ;non-maskable interrupts disabled
;check for 386+
;enable a20
;reinit PICs
mov al, 11h ;ICW1, IC4 bit set, cascade bit clr, edge trig, init bit set
out 20h, al ;send ICW1 to primary pic cmd register
jmp $+2
jmp $+2 ;delay needed on older systems
out 0a0h, al ;send ICW1 to slave pic cmd register
jmp $+2
jmp $+2
mov al, 20h ;ICW2 base address for primary pic = 20h
out 21h, al ;send ICW2 to primary pic data register
jmp $+2
jmp $+2
mov al, 28h ;ICW2 base address for slave pic = 28h
out 0a1h, al ;send ICW2 to slave pic data register
jmp $+2
jmp $+2
mov al, 4 ;ICW3, on primary pic, bits map to irq lines, use irq 2 for cascade
out 21h, al ;send ICW3 to primary pic data register
jmp $+2
jmp $+2
mov al, 2 ;ICW3, on slave pic, byte value = irq line, use irq 2 for cascade
out 0a1h, al ;send ICW3 to slave pic data register
jmp $+2
jmp $+2
mov al, 1 ;ICW4 set bit 1 to enable 80x86 mode
out 21h, al ;send ICW4 to primary pic data register
jmp $+2
jmp $+2
out 0a1h, al ;send ICW4 to slave pic data register
jmp $+2
jmp $+2
xor al, al ;clear the data registers
out 21h, al
jmp $+2
jmp $+2
out 0a1h, al
jmp $+2
jmp $+2
in al, 21h ;only need keyboard and timer irq enabled for now
mov m_pic_mask, al ;store original master pic mask register, restore before exit
or al, 0fch ;mask out all but irq 0 and 1
out 21h, al ;master pic mask updated
jmp $+2
jmp $+2
in al, 0a1h
mov s_pic_mask, al ;store original slave pic mask register, restore before exit
or al, 0ffh ;mask out every slave irq
out 0a1h, al
jmp $+2
jmp $+2
.386p ;calc and insert phys address into gdt entries
xor eax, eax ;clear high word of eax
mov ax, cs ;eax <- code segment address
shl eax, 4 ;multiply segment address by 16 to convert it to physical address
add gdt_addr, eax ;gdt_addr is defined with offset of gdt, gdt_addr + cs*16 = physical addres of gdt
add idt_addr, eax ;idt_addr is defined with offset of idt, idt_addr + cs*16 = physical addres of idt
lidt idt_limit ;load idtr
lgdt gdt_limit ;load gdtr
mov rcode.base_lo, ax
mov rdata.base_lo, ax ;store low word of cs phys address to real mode descriptors
shr eax, 16 ;shift eax to access high word
mov rcode.base_mid, al
mov rdata.base_mid, al ;store middle byte of cs phys address to real mode descriptors
mov rcode.base_hi, al
mov rdata.base_hi, al ;store high byte of cs phys address to real mode descriptors
xor eax, eax ;clear high word of eax
mov ax, seg seg32 ;eax <- seg32 segment address (fixed up by dos at runtime)
shl eax, 4 ;multiply segment address by 16 to convert it to physical address
mov pcode.base_lo, ax
mov pdata.base_lo, ax ;store low word of seg32 phys address to protected mode descriptors
shr eax, 16 ;shift eax to access high word
mov pcode.base_mid, al
mov pdata.base_mid, al ;store middle byte of seg32 phys address to protected mode descriptors
mov pcode.base_hi, al
mov pdata.base_hi, al ;store high byte of seg32 phys address to protected mode descriptors
mov eax, cr0 ;load control register 0
or al, 1 ;set pe bit
mov cr0, eax ;enable protected mode
;manually encoded jmp 8h:start32
db 66h ;specify 32-bit operand
db 0eah ;jmp opcode
dd offset start32 ;32 bit offset
dw 8 ;global descriptor selector (select protected mode code segment)
real_mode: ;transition back to real mode
.386p
mov eax, cr0 ;load control register into eax
and al, 0feh ;clear pe bit
mov cr0, eax ;real mode enabled
db 0eah ;jmp single:real_cs to load cs:ip
dw offset real_cs ;offset real_cs
dw seg single ;segment single (fixed up by dos at runtime)
real_cs: ;back in real mode
.8086
mov ax, cs
mov ds, ax ;ds = cs
mov ss, ax ;ss = cs
mov al, 11h ;ICW1, IC4 bit set, cascade bit clr, edge trig, init bit set
out 20h, al ;send ICW1 to primary pic cmd register
jmp $+2
jmp $+2 ;delay needed on older systems
out 0a0h, al ;send ICW1 to slave pic cmd register
jmp $+2
jmp $+2
mov al, 8 ;ICW2 base address for primary pic = 8
out 21h, al ;send ICW2 to primary pic data register
jmp $+2
jmp $+2
mov al, 70h ;ICW2 base address for slave pic = 70h
out 0a1h, al ;send ICW2 to slave pic data register
jmp $+2
jmp $+2
mov al, 4 ;ICW3, on primary pic, bits map to irq lines, use irq 2 for cascade
out 21h, al ;send ICW3 to primary pic data register
jmp $+2
jmp $+2
mov al, 2 ;ICW3, on slave pic, byte value = irq line, use irq 2 for cascade
out 0a1h, al ;send ICW3 to slave pic data register
jmp $+2
jmp $+2
mov al, 1 ;ICW4 set bit 1 to enable 80x86 mode
out 21h, al ;send ICW4 to primary pic data register
jmp $+2
jmp $+2
out 0a1h, al ;send ICW4 to slave pic data register
jmp $+2
jmp $+2
xor al, al ;clear the data registers
out 21h, al
jmp $+2
jmp $+2
out 0a1h, al
jmp $+2
jmp $+2
mov al, m_pic_mask ;al <- master pic mask
out 21h, al ;master pic mask restored
jmp $+2
jmp $+2
mov al, s_pic_mask ;al <- slave pic mask
out 0a1h, al ;slave pic mask restored
jmp $+2
jmp $+2
.386p
lidt ridt_limit ;setup idtr for real mode
.8086
mov ax, 40h
mov es, ax ;access kbd data area via segment 40h
mov word ptr es:[1ah], 1eh ;set the kbd buff head to start of buff
mov word ptr es:[1ch], 1eh ;kbd buff tail = head to clear kbd buffer
in al, 70h ;al <- cmos ram index register port
and al, 7fh ;clear bit 7 to enable nmi
out 70h, al ;nmi enabled
sti ;interrupts enabled
mov ax, 4c00h ;Terminate process function selected
int 21h ;return to dos
align 2 ;align stack for 16-bit accesses
s16 db 256 dup (0ffh) ;256 byte stack, need at least 256 bytes to change video
single ends ;modes (int 10h) with some vga bios
.386p
seg32 segment use32
assume cs:seg32,ds:seg32,ss:seg32
offset_0: ;used to generate 16-bit offsets in idt descriptor definitions
db "start" ;used to find start of segment in debug
div_err: ;division error isr
xor edi, edi
mov byte ptr es:[edi], '0'
hlt
iretd
dont_care: ;rare/obscure faults and exceptions
xor edi, edi
mov byte ptr es:[edi], '1'
hlt
iretd
nmi: ;non maskable interrupt isr
xor edi, edi
mov byte ptr es:[edi], '2'
hlt
iretd
invalid_op: ;invalid opcode isr
xor edi, edi
mov byte ptr es:[edi], '3'
hlt
iretd
double_fault: ;double fault isr
xor edi, edi
mov byte ptr es:[edi], '4'
hlt
iretd
fpu_err: ;fpu error isr
xor edi, edi
mov byte ptr es:[edi], '5'
hlt
iretd
not_present: ;descriptor not present isr
xor edi, edi
mov byte ptr es:[edi], '6'
hlt
iretd
gp_fault: ;general protection fault isr
xor edi, edi
mov byte ptr es:[edi], '7'
hlt
iretd
pit_isr: ;int 20h timer isr
push eax
mov al, 20h
out 20h, al
pop eax
iretd
kbd_isr: ;int 21h keyboard isr
push eax
in al, 60h
mov al, 20h
out 20h, al
pop eax
iretd
sp16 dw ? ;16-bit stack pointer
start32:
mov ax, 10h
mov ds, ax ;ds <- protected mode data descriptor (same physical address as code descriptor)
mov fs, ax
mov gs, ax ;setup extra segments
mov ss, ax ;setup stack segment
mov sp16, sp ;store old stack pointer, restore before returning to real mode
mov esp, offset s32_end ;setup 32-bit stack pointer
mov ax, 30h
mov es, ax ;es <- vga compatible text buffer
sti ;ready for interrupts, leave nmi disabled
call func1
exit_pm: ;return to real mode
cli ;interrupts disabled
mov sp, sp16 ;restore 16-bit stack pointer
mov ax, 20h
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax ;load real mode data descriptor selectors
db 0eah ;jmp 18h:ret_real to load real mode code descriptor
dd offset real_mode ;offset to 16-bit code in single segment
dw 18h ;real mode code selector
db "call_here" ;use this to find call target in debug
func2 proc
push eax
push ebx
push ecx
push edx
push esi
pop esi
pop edx
pop ecx
pop ebx
pop eax
ret
func2 endp
func1 proc
push eax
push ebx
push ecx
push edx
push esi
;do arbitrary work
mov eax, 934875h
xor eax, ebx
inc ecx
mul edx
add edx, 94357h
jmp target1
xor ecx, ecx
add edx, 987h
dec esi
target1:
call func2 ;IT NEVER MAKES IT TO FUNC2
jmp over_marker
db "calladdress" ;use this to find call instruction in debug
over_marker:
pop esi
pop edx
pop ecx
pop ebx
pop eax
ret
func1 endp
align 4 ;align stack for 32-bit accesses
s32 db 256 dup (0ffh) ;256 byte stack
s32_end: ;used to initialize esp
seg32 ends
end start
我认为问题在于 MASM 生成了错误的调用目标,而我正在执行垃圾。
我通过使用调试加载程序来测试这一点(只是为了检查操作码。)调试将调用指令加载到 06CA:05A9
和调用目标(push eax
) 到 06CA:057B
。调用指令编码为E8 CD FF 00 00
,即call loc_0000ffd2
。
如果是 16 位段,0x5a9 加上 0xffd2 将转入 0x57b。或者偏移量可能是有符号的并且是负数?我是否使用了错误的调用类型?
最佳答案
问题是 MASM 5.10 链接器有缺陷,无法正确处理这种 32 位重定位。正如您怀疑的那样,它将 32 位相对位移视为 16 位值,正如您所正确观察到的那样,它会产生错误的值(特别是在以负位移调用代码时)。为了测试您的代码,我一直使用 MASM 5.10a,链接器版本为 3.64。
您可以继续使用 MASM.EXE 5.10a,但需要替换链接器。 MASM 6.11 附带的 16 位 Microsoft Overlay Linker (LINK.EXE) 可以正常工作。您需要有一个扩展的内存管理器,LINK.EXE 和/或 MASM.EXE 才能正常运行。 MASM 6.11 是可以从 DOS 运行的 MASM 产品的最后一个版本。 MASM 6.11 安装盘可以从 here 下载.
<小时/>如果您下载并安装Borland's Turbo Assembler v2.0x您可以使用 TASM 汇编代码并使用 TLINK 链接。如果您在 TASM 生成的目标文件上运行 TLINK,它实际上会警告您此问题!错误将类似于:
32-bit record encountered in module Use "/3" option
如果您使用 /3
选项,它将启用 32 位处理并应生成正确的可执行文件。
要使用 TASM 进行组装(它仍可与 MASM 一起使用),必须对这些行进行小幅调整:
lidt idt_limit ;load idtr
lgdt gdt_limit ;load gdtr
...
lidt ridt_limit ;setup idtr for real mode
TASM 对类型很挑剔,它们必须写成:
lidt fword ptr idt_limit ;load idtr
lgdt fword ptr gdt_limit ;load gdtr
...
lidt fword ptr ridt_limit ;setup idtr for real mode
<小时/>
JWasm 是一个兼容 MASM 的开源解决方案,基于 Watcom 的汇编器 (WASM),并具有更现代的更新。 JWAsm 还可以在 Windows、Linux、MacOS 等其他平台上构建和运行。JWasm 能够像 MASM 一样将文件组装为 DOS 对象文件 (OMF),但它还具有集成的 16 位链接器,允许您构建DOS MZ 直接可执行。您可以从 here 下载预构建的 DOS 版本的 JWASM .
JWasm 像 TASM 一样对类型很挑剔,因此请参阅有关 fword ptr
的 TASM 部分
要将单个源汇编文件汇编并链接到 DOS 可执行文件,您只需执行以下操作:
jwasmr -mz filename.asm
这应该生成一个名为filename.exe
的文件
关于assembly - MASM 在保护模式下生成错误的调用目标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61955769/
我已经使用 vue-cli 两个星期了,直到今天一切正常。我在本地建立这个项目。 https://drive.google.com/open?id=0BwGw1zyyKjW7S3RYWXRaX24tQ
您好,我正在尝试使用 python 库 pytesseract 从图像中提取文本。请找到代码: from PIL import Image from pytesseract import image_
我的错误 /usr/bin/ld: errno: TLS definition in /lib/libc.so.6 section .tbss mismatches non-TLS reference
我已经训练了一个模型,我正在尝试使用 predict函数但它返回以下错误。 Error in contrasts<-(*tmp*, value = contr.funs[1 + isOF[nn]])
根据Microsoft DataConnectors的信息我想通过 this ODBC driver 创建一个从 PowerBi 到 PostgreSQL 的连接器使用直接查询。我重用了 Micros
我已经为 SoundManagement 创建了一个包,其中有一个扩展 MediaPlayer 的类。我希望全局控制这个变量。这是我的代码: package soundmanagement; impo
我在Heroku上部署了一个应用程序。我正在使用免费服务。 我经常收到以下错误消息。 PG::Error: ERROR: out of memory 如果刷新浏览器,就可以了。但是随后,它又随机发生
我正在运行 LAMP 服务器,这个 .htaccess 给我一个 500 错误。其作用是过滤关键字并重定向到相应的域名。 Options +FollowSymLinks RewriteEngine
我有两个驱动器 A 和 B。使用 python 脚本,我在“A”驱动器中创建一些文件,并运行 powerscript,该脚本以 1 秒的间隔将驱动器 A 中的所有文件复制到驱动器 B。 我在 powe
下面的函数一直返回这个错误信息。我认为可能是 double_precision 字段类型导致了这种情况,我尝试使用 CAST,但要么不是这样,要么我没有做对...帮助? 这是错误: ERROR: i
这个问题已经有答案了: Syntax error due to using a reserved word as a table or column name in MySQL (1 个回答) 已关闭
我的数据库有这个小问题。 我创建了一个表“articoli”,其中包含商品的品牌、型号和价格。 每篇文章都由一个 id (ID_ARTICOLO)` 定义,它是一个自动递增字段。 好吧,现在当我尝试插
我是新来的。我目前正在 DeVry 在线学习中级 C++ 编程。我们正在使用 C++ Primer Plus 这本书,到目前为止我一直做得很好。我的老师最近向我们扔了一个曲线球。我目前的任务是这样的:
这个问题在这里已经有了答案: What is an undefined reference/unresolved external symbol error and how do I fix it?
我的网站中有一段代码有问题;此错误仅发生在 Internet Explorer 7 中。 我没有在这里发布我所有的 HTML/CSS 标记,而是发布了网站的一个版本 here . 如您所见,我在列中有
如果尝试在 USB 设备上构建 node.js 应用程序时在我的树莓派上使用 npm 时遇到一些问题。 package.json 看起来像这样: { "name" : "node-todo",
在 Python 中,您有 None单例,在某些情况下表现得很奇怪: >>> a = None >>> type(a) >>> isinstance(a,None) Traceback (most
这是我的 build.gradle (Module:app) 文件: apply plugin: 'com.android.application' android { compileSdkV
我是 android 的新手,我的项目刚才编译和运行正常,但在我尝试实现抽屉导航后,它给了我这个错误 FAILURE: Build failed with an exception. What wen
谁能解释一下?我想我正在做一些非常愚蠢的事情,并且急切地等待着启蒙。 我得到这个输出: phpversion() == 7.2.25-1+0~20191128.32+debian8~1.gbp108
我是一名优秀的程序员,十分优秀!