Convert Instruction in assembly code lods and stos so NASM can compile

后端 未结 2 1713
长发绾君心
长发绾君心 2021-01-21 07:11

Ok so I am trying to assemble some code in assembly using nasm -f elf final.asm:

xor eax,eax
push eax
push dword(0x75792273)
push dword(0x70742027)
         


        
2条回答
  •  星月不相逢
    2021-01-21 08:04

    Use lodsb / lodsw / lodsd / lodsq to indicate operand-size with the mnemonic itself, not with operands.

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


    Intel's LODS documentation suggests that you can use operands as documentation and to imply an operand-size (and segment override), like you're trying to do, as an alternative to an operand-size suffix.

    This explicit-operands form is provided to allow documentation; however, note that the documentation provided by this form can be misleading. That is, the source operand symbol must specify the correct type (size) of the operand (byte, word, or doubleword), but it does not have to specify the correct location. The location is always specified by the DS:(E)SI registers, which must be loaded correctly before the load string instruction is executed.

    Presumably the designers of NASM syntax decided that allowing lods byte [r15] to assemble was a bad idea, and disallowing the one-operand form entirely was easier than writing a bunch of code just to check that the given operand is what it's supposed to be.

    Since NASM has a prefix syntax for segment/operand/address overrides, fs lodsb lets you write what would otherwise need an operand to attach a segment override to (like lodsb fs:[rsi] in MASM syntax.)

    Doing it this way makes the string instructions non-special as far as the assembler is concerned; they're just another entry in a table mapping mnemonics to opcodes. If Intel's own syntax included mnemonic prefixes for machine-code prefix bytes, they might have made the same design choice.

    Fun fact: STOS's segment can't be overridden (from ES). Perhaps Intel wanted to share more transistors with the original 8086 implementation of MOVS, where a segment override only affects the [DS:SI] source, not the [ES:DI] destination.


    other assemblers:

    GNU .intel_syntax supports segment prefix syntax, but not NASM's o16/o32/o64 or a16/a32/a64 operand and address-size specifiers.

    # 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'
    

    I don't see a way to write an address-size override without using an explicit operand for string instructions in GNU syntax (AT&T or Intel).

    objdump -Mintel output of the same:

       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]
    

提交回复
热议问题