1

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

Hawken
  • 1,988
  • 17
  • 34

1 Answers1

5

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

Community
  • 1
  • 1
osgx
  • 85,909
  • 48
  • 329
  • 491
  • Can you explain, Where are you implementing a call? – osgx Oct 11 '12 at 01:13
  • well not a real call, but trying to save `%ip` into `%dx` (since I am not using %dx in my tiny subroutine), `jmp` to my subroutine, and then `jmp *%dx` to return. – Hawken Oct 11 '12 at 01:19
  • Why not to use default stack and call/ret instead of jmp/jmp *dx? And I still see no obstacles to call/pop dx. – osgx Oct 11 '12 at 01:39
  • the purpose of this was to be used in helping me print out %ss in hex, since I have no idea where the stack is starting; I wanted to "call" my `convert_nibble_to_hex` subroutine with using the stack – Hawken Oct 11 '12 at 02:04
  • but pair of `call near`/`pop dx` will compensate ss changes and after pair ss will be the same. call internals are listed here: http://www.fermi.mn.it/linux/quarta/x86/call.htm Other variant is just save ss in dx and call your function as usual to print dx register. – osgx Oct 11 '12 at 02:10
  • I don't have any idea where the stack is, that's why I wanted to print out `%ss`. If I remember correctly %ip starts at `$0x07c0` though – Hawken Oct 11 '12 at 02:18
  • May be you need a debugger to find some information about your environment? – osgx Oct 11 '12 at 02:20
  • my environment is just BIOS+PXE x86 real mode, this is mostly just for the sake of learning assembly; anyway, you have answered my question, reading/writing to `%ip` is not possible. – Hawken Oct 11 '12 at 02:27
  • 2
    The problem with a `call/pop` sequence is that you need a working stack for that, which might not be the case during OS startup. – Gunther Piez Oct 11 '12 at 09:50
  • @hirschhornsalz in retrospect maybe that's the question I should have asked, for what I needed I just worked around using a function, though from what I know now, I think there is actually a stack, albeit a small one, provided by the bios. – Hawken Oct 15 '12 at 21:36