首页 文章

在汇编代码lods和stos中转换指令,以便NASM可以编译

提问于
浏览
2

好的,我正在尝试使用 nasm -f elf final.asm 在汇编中汇编一些代码:

xor eax,eax
push eax
push dword(0x75792273)
push dword(0x70742027)
push dword(0x77777875)
push dword(0x20237678)
push dword(0x76727827)
push dword(0x27797175)
push dword(0x75711225)
push dword(0x72747676)
push dword(0x74231476)
push dword(0x70707470)
push dword(0x23247077)
push dword(0x78707822)
push dword(0x24711174)
push dword(0x22707373)
push dword(0x78717974)
push dword(0x75771777)
push dword(0x70777125)
push dword(0x73731472)
push dword(0x71277377)
push dword(0x79251822)
push dword(0x79707478)
push dword(0x78742779)
push dword(0x72727871)
push dword(0x71251475)
push dword(0x27247772)
push dword(0x79757479)
push dword(0x70227071)
push dword(0x77737420)
push dword(0x70251970)
push dword(0x74747127)
push dword(0x23277677)
push dword(0x79712024)
push esp
pop esi
mov edi,esi
mov edx,edi
cld
mov ecx,0x80
mov ebx,0x41
xor eax,eax
push eax
lods byte[esi]
xor eax,ebx
stos byte[es:edi]
loop 0xb7
push esp
pop esi
int 0x3

这导致以下错误:

final.asm:44: error: parser: instruction expected
final.asm:46: error: parser: instruction expected

我找到了这些错误的答案:NASM: parser: instruction expected rep movs

基本上,这表明NASM不承认lods和stos指令 . 这意味着我需要将它们转换为NASM确实识别的内容,以便获得相同的结果 .

我的问题是,我可以更改这两行,以便NASM可以编译它,以便我最终可以调试它 .

2 回答

  • 2

    lodsb 的作用是:

    mov al,[esi]
    inc esi           ; (or dec, according to direction flag)
    

    你也可以用
    lodsw 加载单词(到 ax ,将 esi 加2),或者
    lodsd 加载dwords(至 eax ,将 esi 加4) .

    stosb

    mov [es:edi],al
    inc edi
    

    同样在这里, stoswstosd 将存储2或4个字节(并相应地调整 edi

    首先从内存加载,由SOURCE(ESI)寄存器指向,后者写入DESTINATION(ES:EDI)寄存器指向的内存 .

    您不需要(也不能)指定将使用哪些寄存器 . 来源永远是E S 我,而目的地总是E D


    在段寄存器上编辑: lods 指令可以与段覆盖前缀一起使用(即 ss lodsb ) . stos 指令固定为 es (原始答案中缺少详细信息)段使用,并且无法覆盖 .

    movsb/movsw/movsd 指令( size*(mov [es:edi],[ds:esi] inc esi inc edi) )也可以在源端覆盖,即 . es movsb 将从 es:esi 而不是 ds:esi 获取字节,但目标段寄存器固定为 es .

  • 3

    使用 lodsb / lodsw / lodsd / lodsq 用助记符本身表示操作数大小,而不是操作数 .

    Remove the byte [esi] part, NASM won't accept explicit operands for string instructions.


    Intel's LODS documentation建议您可以使用操作数作为文档,并暗示操作数大小(和段覆盖),就像您尝试做的那样,作为操作数大小后缀的替代 .

    提供此显式操作数表单以允许文档;但请注意,此表单提供的文档可能会产生误导 . 也就是说,源操作数符号必须指定操作数(字节,字或双字)的正确类型(大小),但不必指定正确的位置 . 该位置始终由DS:(E)SI寄存器指定,必须在执行加载字符串指令之前正确加载 .

    据推测,NASM语法的设计者决定允许 lods byte [r15] 汇编是一个坏主意,完全不允许单操作数形式比编写一堆代码更容易,只是为了检查给定的操作数是否应该是它应该是什么 .

    由于NASM具有用于段/操作数/地址覆盖的前缀语法, fs lodsb 允许您编写原本需要操作数来附加段覆盖的内容(如MASM语法中的 lodsb fs:[rsi] ) .

    就汇编程序而言,这样做会使字符串指令非特殊;它们只是将表格助记符映射到操作码的表中的另一个条目 . 如果英特尔自己的语法包含机器代码前缀字节的助记符前缀,那么它们可能已经做出了相同的设计选择 .

    有趣的事实:STOS 's segment can' t被覆盖(来自ES) . 也许英特尔希望与原始的8086实现MOVS共享更多晶体管,其中段覆盖仅影响 [DS:SI] 源,而不影响 [ES:DI] 目的地 .


    other assemblers

    GNU .intel_syntax 支持段前缀语法,但不支持NASM的 o16 / o32 / o64a16 / a32 / a64 操作数和地址大小说明符 .

    # assembled with as --32    disassembled with ndisasm -b 32
    .intel_syntax noprefix
    
        mov    al, byte ptr fs:[esi]
                        00000038  648A06            mov al,[fs:esi]
    
        gs lodsb
                        0000003B  65AC              gs lodsb
        lods   dword ptr ss:[ecx]
        # Warning: `dword ptr ss:[ecx]' is not valid here (expected `[esi]')
                        0000003D  36AD              ss lodsd
        ss lodsd   [si]
                        0000003F  3667AD            ss a16 lodsd
        lods   eax, dword ptr ss:[esi]
                        00000042  36AD              ss lodsd
    
    #lods al      # Error: operand type mismatch for `lods'
    #fs es lodsd  # Error: same type of prefix used twice
    #a16 lodsb    # Error: no such instruction: `a16 lodsb'
    

    我没有看到在GNU语法(AT&T或Intel)中使用字符串指令的显式操作数来编写地址大小覆盖的方法 .

    objdump -Mintel 输出相同:

    4:   64 8a 06                mov    al,BYTE PTR fs:[esi]
       7:   65 ac                   lods   al,BYTE PTR gs:[esi]
       9:   36 ad                   lods   eax,DWORD PTR ss:[esi]
       b:   36 67 ad                lods   eax,DWORD PTR ss:[si]
       e:   36 ad                   lods   eax,DWORD PTR ss:[esi]
    

相关问题