【问题标题】:Assembly: [SI + CX] = impossible combination of address sizes汇编:[SI + CX] = 地址大小的不可能组合
【发布时间】:2013-12-26 14:39:40
【问题描述】:

所以,今天我尝试为我正在开发的操作系统创建一个库,它具有一个简单的功能:在屏幕上打印字符。要使用这个函数,我只需要将字符串地址压入堆栈并调用它(字符串必须以 0x00 字节结尾)。下面是函数的源代码:

__print:                        ;Print string that is terminated with a 0x00 to screen

__print_prepare:
    pop si                  ;SI Register = String Address
    mov ah, 0x0E                ;0x0E Function = Print Character on screen
    mov bx, 0x0F                ;Background = Black, CharColor = White
    xor cx, cx              ;Counter = 0

__print_check:
    push byte [cx + si]         ;Push character to the stack
    or byte [cx + si], byte [cx + si]   ;Check if the byte equals 0x00
    jz __print_exit             ;If true then exit
    jmp __print_main            ;Else print the character

__print_main:
    pop al                  ;Store the byte in the AL Register
    int 0x10                ;Call interupt 0x10 = BIOS Interupt
    jmp __print_next            ;Continue to next character

__print_next:
    inc cx                  ;Increment CX Register by one for next character = Counter
    jmp __print_check           ;Check authenticity of character

__print_exit:
    ret
    

每当我尝试汇编源代码时,都会出现以下 nasm 错误:

def_os_lib.asm:10: 错误:操作码和操作数的组合无效

def_os_lib.asm:11: 错误:操作码和操作数的组合无效

def_os_lib.asm:16: 错误:操作码和操作数的组合无效

另外,在某些情况下,也就是我用ELF格式编译的时候,会提示这个错误:

def_os_lib.asm:10: 错误:地址大小的不可能组合

def_os_lib.asm:11: 错误:地址大小的不可能组合

我用于 nasm(bin) 的命令是:

nasm -f bin def_os_lib.asm

我用于 nasm(elf64) 的命令是:

nasm -f elf64 def_os_lib.asm

我刚刚开始组装,我知道我迈出了一大步。我只是想再深入一点。

感谢大家的帮助。通过纠正您的建议,我已经完成了源代码。这是新代码:

__print:                        ;Print string that is terminated with a 0x00 to screen

__print_prepare:
    pop si                  ;SI Register = String Address
    xor bx, bx              ;Counter = 0

__print_check:
    push bx                 ;Save BX
    xor ax, ax              ;AX = 0
    add bx, si              ;BX = Address of the character
    mov al, byte [bx]           ;AL = Character
    pop bx                  ;Restore BX
    push ax                 ;Save character
    or ax, ax               ;Check if the byte equals 0x00
    jz __print_exit             ;If true then exit
    jmp __print_main            ;Else print the character

__print_main:
    pop ax                  ;Store the byte in the AL Register
    push bx                 ;Save BX
    mov bx, 0x0F                ;Background = Black, CharColor = White
    mov ah, 0x0E                ;0x0E Function = Print Character on screen
    int 0x10                ;Call interupt 0x10 = BIOS Interupt
    jmp __print_next            ;Continue to next character

__print_next:
    pop bx                  ;Restore BX
    inc bx                  ;Increment CX Register by one for next character = Counter
    jmp __print_check           ;Check authenticity of character

__print_exit:
    ret
    

【问题讨论】:

    标签: assembly operating-system nasm interrupt cpu-registers


    【解决方案1】:

    推送字节[cx + si]

    cx cannot be used in adressing under real mode.

    或字节[cx + si],字节[cx + si]

    在 x86 中,一条指令通常不能有两个内存操作数。您需要使用寄存器作为中间人。

    【讨论】:

    • 所以我需要将这些值移动到另一个寄存器,然后使用 or 本身...
    • 您只需要复制其中一个值。
    【解决方案2】:

    您只能将 [BX 或 BP] 与 [SI 或 DI] 结合使用;不允许使用 AX、DX 或 CX。

    你不能 PUSH/POP 一个字节所以 POP AL 所以任何字节大小的参数都将被视为无效。

    【讨论】:

    • 你的意思是在push中不需要byte语句?
    • byte 指令指定参数的大小为字节。你不能 PUSH/POP 一个字节。
    • Magoo,实际上你可以推动 al,只有汇编程序不让你这样做。它是“最近”从气体中删除的,可能是从 nasm 中删除的,因为正如您所解释的那样,这不是一个好主意。
    • @AlexisWilke 嗯,不,x86 架构不支持字节推送/弹出。汇编器可能没有反对,并在指定字节时执行了字指令,但这是汇编器中的一个错误——即使它被利用了。现在您可以将 push-byte 实现为宏,但它需要是 dec sp mov [sp+1],al 或其他或可能是 mov [sp],al dec sp 但它肯定不会有效。我相信你会发现,如果push al被编码,实际实现的是push ax。如果你有旧版本,我很想看看 push al 被组装成什么字节码。
    • 实际上应该是这样的:dec sp mov [sp],al——实际上你是对的,你可以压入堆栈的最小大小是一个单词。但是,在 x86 上使用至少 32 位和在 amd64 上不至少 64 位的任何值是不安全的,这是正确的……这些天通常会检查堆栈对齐。
    猜你喜欢
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多