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

时间:2016-10-17 17:16:33

标签: assembly nasm

好的,我正在尝试使用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 个答案:

答案 0 :(得分:4)

lodsb的作用是:

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

你也可以使用
lodsw要加载字词(ax,{2}增加esi)或
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

答案 1 :(得分:2)

使用lodsb / lodsw / lodsd / lodsq表示操作数大小与助记符本身,表示操作数。

删除byte [esi]部分,NASM不接受字符串指令的显式操作数。

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

  

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

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

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

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

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

其他汇编程序

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&amp; 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]