Converting [symbol + constant] Intel syntax addressing mode to AT&T syntax?

前端 未结 2 1611
Happy的楠姐
Happy的楠姐 2021-01-28 10:13

I just cant figure out how to add an offset to my destination when moving a value, specifically in Intel syntax I have:

MOV   [gdtr + 2], EAX

a

相关标签:
2条回答
  • 2021-01-28 11:02

    It's just gdtr+2

    gdtr(2,1) [gives an error] but using just gdtr(,1) works fine.

    The stuff inside the () parens in an AT&T addressing mode can only be registers (and a scale factor): disp(base, index, scale). Base and index are optional so empty is fine but invalid (non-register) is not.

    And when you specify a scale with no base or index, apparently you must use only one comma: (,,1) is an error about an empty scale factor.
    You could write it as gdtr+2(,1) to explicitly use no registers.

    The +2 is part of the displacement in an addressing mode, not the base or index registers, regardless of syntax. See A couple of questions about [base + index*scale + disp] or Intel or AMD's manual about how addressing modes are encoded. (What you're doing is the [disp32] or [disp16] addressing mode, in terms of how it's going to be encoded into machine code.)

    As Nate pointed out, the linker takes care of turning assemble-time literal constants + link-time-constant symbol addresses into a final address in the machine code, encoded as a disp32 (or disp16 for 16-bit address size). Or RIP-relative rel32 for x86-64.

    Fun fact: some AT&T assemblers accept (gdtr) as an alternative to gdtr, but not 2(gdtr).


    Ways to solve this yourself:

    Normally if you're stuck on NASM -> AT&T you can assemble NASM source (e.g. nasm -felf) and disassemble with an AT&T disassembler like objdump -drwC. But that doesn't help here for symbolic addressing mode syntax because at best objdump -dr just annotates numeric addressing modes with symbol name info.

    So in this case your best bet is to get GCC or clang to emit an instruction that uses a symbol name and a numeric constant, like this

    char gdtr[1024];                // global var so it has a symbol
    char foo() { return gdtr[2]; }  // load from global symbol + constant.
    

    compiles with gcc9.3 -O2 -m32 on the Godbolt compiler explorer to this asm:

    foo:
            movzbl  gdtr+2, %eax
            ret
    gdtr:
            .zero   1024
    

    There's your addressing mode, and as a bonus the AT&T mnemonic for movzx with a byte source. Of course you can fiddle with the types.

    Compilers are useful resources; they know how to do lots of things "the normal way" when compiling simple C functions, and they know the calling convention and type widths. And AT&T syntax for everything including function pointers. If you're stuck, ask a compiler. Basically the only thing you can't get a compiler to show you is the syntax for jmp far (AT&T ljmp)

    0 讨论(0)
  • 2021-01-28 11:13

    Simply write

    movl %eax, gdtr+2
    

    Base-offset addressing only works when the offset is a register. There's no point in having an addressing mode to add two constants together; the way this works (regardless of syntax) is that the assembler / linker resolve symbol+constant into a a single number for the displacement field of the instruction encoding.

    0 讨论(0)
提交回复
热议问题