flat assembler
Message board for the users of flat assembler.

Index > OS Construction > mov ax, [sp], error: reserved word used as symbol

Author
Thread Post new topic Reply to topic
antonyprojr



Joined: 31 May 2015
Posts: 3
antonyprojr 02 Aug 2019, 17:35
How to read the value that Instruction Pointer(IP) had before entering on the interrupt and before to restore to this position through iret on real mode x86, supposed to be on the stack?

I've tried:
Code:
mov ax, [sp]    

but i got this error:
Quote:
error: reserved word used as symbol.


The purpose is implement a (very poor) context switch using system timer interrupt.
Post 02 Aug 2019, 17:35
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20418
Location: In your JS exploiting you and your system
revolution 02 Aug 2019, 18:15
In 16-bit mode only SI, DI, BX and BP can be used to address memory.

You will need to use something like this:
Code:
mov bp,sp
mov ax,[bp]    
If you need you can also save the value of BP:
Code:
push bp
mov bp,sp
mov ax,[bp+2]
pop bp    
BP is usually the register of choice since it will use SS by default. If you use another register then you might need to add the SS override.
Code:
mov ax,[ss:bx+2]    
Post 02 Aug 2019, 18:15
View user's profile Send private message Visit poster's website Reply with quote
fpissarra



Joined: 10 Apr 2019
Posts: 64
fpissarra 03 Aug 2019, 15:01
@revolution is totally right pointing out that only BX, BP, SI and DI can be used as pointers to access memory in 16 bits pre 386 instruction set. The flexible way, where you can use ANY register, was introduced by 80386 and can be used in 16 bits code (unless your processor is pre 386!)...

For example, all instructions below will cause the same error in 16 bits, pre 386, code:
Code:
mov ax,[dx] ; DX cannot be used this way!
mov ax,[bx+dx] ; BX is 'right', but DX isn't!    

Another thing that isn't available to pre 386 instruction set is scaling:
Code:
mov ax,[bx+2*si+2]   ; 2*si isn't available!    

Here we use BX and SI, but scaling isn't available!

BUT... you can use 386 instruction set in 16 bits mode if you want:
Code:
mov ax,[ebx+2*esi+2]  ; This WORKS!    

In 16 bits code the upper 16 bits of 32 bits registers are discarded. The logical address is still calculated by ((segment << 4) + offset), there the physical address is 20 bits long and each part (segment and offset) are 16 bits. And, using 32 bits registers you can use ANY registers as you intended:
Code:
mov ax,[esp]    

You don't need to zero the upper 16 bits of ESP to use this.

The penalty is, when using 32 bits registers as pointers, like this, the compiler will prefix your instruction with 0x67. When using 32 bits registers as source or targets of an instruction the prefix 0x66 is added. See this example:
Code:
8B 07         mov ax,[bx]
66 8B 07      mov eax,[bx]
67 8B 03      mov ax,[ebx]
66 67 8B 03   mov eax,[ebx]    
Post 03 Aug 2019, 15:01
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20418
Location: In your JS exploiting you and your system
revolution 03 Aug 2019, 15:08
fpissarra wrote:
In 16 bits code the upper 16 bits of 32 bits registers are discarded. The logical address is still calculated by ((segment << 4) + offset), there the physical address is 20 bits long and each part (segment and offset) are 16 bits.
I can't test this right now, but I think that is not correct. IIRC the full 32-bit address is computed and used. Because these instruction are 32-bit instructions when the address override prefix is used.

There is also the matter of the limit value in the hidden shadow segment bits. If the address exceeds the limit then the CPU generates an exception. We can use unreal-mode to set the limit to another value, but that starts to get into more advanced usage of the CPU.
Post 03 Aug 2019, 15:08
View user's profile Send private message Visit poster's website Reply with quote
fpissarra



Joined: 10 Apr 2019
Posts: 64
fpissarra 03 Aug 2019, 15:30
revolution wrote:
I can't test this right now, but I think that is not correct. IIRC the full 32-bit address is computed and used.


revolution wrote:
There is also the matter of the limit value in the hidden shadow segment bits. If the address exceeds the limit then the CPU generates an exception. We can use unreal-mode to set the limit to another value, but that starts to get into more advanced usage of the CPU.


"In 16 bits code" as in "in real mode"... There is no "exception" of this kind in real mode. For example, the logical address 0xffff:0xffff will result in a 21 bits physical address (0x10FFEF), but if Gate A20 isn't enabled the memory access will be at address 0x0FFEF (20 bits long). If it is enabled the processor will access the extra segment above 1 MiB limit (That's what HIMEM.SYS in old DOS allows you to do)...

In protected mode pos-386 you should use 32 bits registers, but in REAL MODE you can use them without any worries about the attributes in GDT or LDT...

Anyway... in real mode, using 32 bits registers to calc the effective address, all 32 bits ARE used, but the memory access will be limited (by hardware and processor mode) to 21 bits, max...
Post 03 Aug 2019, 15:30
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20418
Location: In your JS exploiting you and your system
revolution 03 Aug 2019, 15:37
Real mode can still access the 32-bit instructions and registers with the 0x66 and 0x67 override prefixes. You need to be careful about not exceeding the address range by using addresses too large. For 16-bit instructions using BX (not EBX) then what you say is correct, the BX register cannot exceed 2^16, but EBX can.
Code:
use16
mov ebx,0xfff00000
mov ax,[bx] ;okay
mov ax,[ebx] ;fault in real mode, address exceeds the limit of 0xffff for DS segment    
fpissarra wrote:
Anyway... in real mode, using 32 bits registers to calc the effective address, all 32 bits ARE used, but the memory access will be limited (by hardware and processor mode) to 21 bits, max...
The CPU doesn't have any such masking. That is why the A20 gate needed to be implemented, to externally limit the address range. But it can be defeated by using 32-bit registers to generate any address. Usually the limit in the segment shadow bits will trap such bad addresses, but in unreal mode that limit can be extended and the full 32-bit address range can be accessed.
Post 03 Aug 2019, 15:37
View user's profile Send private message Visit poster's website Reply with quote
antonyprojr



Joined: 31 May 2015
Posts: 3
antonyprojr 03 Aug 2019, 20:14
I need to correct myself, i said that my OS was in real mode, well, my code is based in the open source MichalOS project https://sourceforge.net/projects/michalos/ (written with Netwide Assembler, but i ported it to Flat Assembler) it's clearly described that the OS works is UNreal mode, not in real mode as i said. When I change the interrupt 1Ch location(to handle the timer interrupt where i want to make the context switch), I'm already in UNreal mode.

Sorry for that! Embarassed

So, rephrasing: How to read IP(Instruction Pointer) in Big UNreal Mode, where memory access is up to 4GB, but the code limited to 64KB, when interrupt 1Ch is triggered? (Inside the interrupt, to where iret command will return when called).
Post 03 Aug 2019, 20:14
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20418
Location: In your JS exploiting you and your system
revolution 03 Aug 2019, 21:07
In real and unreal modes (which are the same thing actually just with a different limit for each segment register) the stack pointer (E)SP is not saved by an interrupt. (E)SP will still be whatever the interrupted task was using less six bytes (or four bytes for software interrupts) for the saved CS, IP, and flags values. So you can use BP (or ESP) to access the saved IP value on the stack.
Post 03 Aug 2019, 21:07
View user's profile Send private message Visit poster's website Reply with quote
antonyprojr



Joined: 31 May 2015
Posts: 3
antonyprojr 08 Aug 2019, 02:49
With help of @revolution and debug with Bochs, i can see that the Instruction Pointer can be easily accessed inside the interrupt by:

Code:
mov ax, [bp – 8] ;Now IP is in ax    


Thank you all of yours for the help! Very Happy
Post 08 Aug 2019, 02:49
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.