Search code examples
assemblygnu-assembleratt

GAS does not recognise register %ip


In my 16bit program GAS is balking at the instruction:

movw %ip, %dx

I find this strange as moving a segment register works fine, for example:

movw %ss, %ax

The full error message is:

Error: bad register name `%ip'

And my version string is:

GNU assembler (GNU Binutils) 2.22


Solution

  • Unfortunately, not every register can be easily accessed. There are some limitations.

    As listed in x86 wikibook, GPR section, in x86 there are 8 General-Purpose Registers (GPRs): AX, CX, DX, BX, SP, BP, SI, DI, which can be used in many commands. They are encoded as 3 bits; and there is no space in the instruction encoding to encode Special registers, like EIP (IP), or EFLAGS (FLAGS).

    If you scroll wikibook down, there is a section about IP:

    Instruction Pointer

    The EIP register contains the address of the next instruction to be executed if no branching is done.

    EIP can only be read through the stack after a call instruction.

    So, it is really illegal to use mov to read IP.

    There are some examples of reading ip with call then pop %ax sequence here: http://www.programmersheaven.com/mb/x86_asm/267963/267963/how-to-access-ip-register/

    Update: About reading of SS register:

    There are actually many variant of mov instruction encoding, e.g. in this table we see segment reading

     mnemonic   op1 op2 po     o    description, notes 
     MOV    Sreg    r/m16   8E     r        Move
    

    or Control Register writing:

     MOV    r32 CRn 0F20   r ...    Move to Control Registers
    

    but there is still no MOV for IP register.

    Update2: in x86_64 there is a reading of EIP with LEA, according to https://stackoverflow.com/a/1047968/196561