OSDev.org

The Place to Start for Operating System Developers
It is currently Fri May 26, 2017 6:53 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 8:22 am 
Offline
User avatar

Joined: Wed Nov 02, 2016 2:20 am
Posts: 6
Hi,

I have some pieces of code for dev86/bcc (mostly inline assembly), both of them are working fine. Now I'm trying to use this with nasm, but my code won't work.

Maybe some of you guys can help me.

First, the working C code:
Code:
uint16_t get_mem(uint16_t seg, uint16_t off) {
   #asm
      mov bx, sp
      mov es, [bx+2]   ; seg
      mov   bx, [bx+4]   ; off
      seg   es
      mov   ax, [bx]
   
   
   #endasm
}

/* write a 16bit word to an absolute location in SEG:OFF format */
void set_mem(uint16_t seg, uint16_t off, uint16_t data) {
   #asm
      mov bx, sp
      mov es, [bx+2]   ; seg
      mov ax, [bx+6]   ; data
      mov bx, [bx+4]   ; off
      seg es
      mov [bx], ax
   #endasm
}


And here's the not-working code for nasm:
Code:
; get a 16bit word from an absolute location in SEG:OFF format
; takes SEG:OFF in DX:AX
; returns data in  AX
get_mem:
   pusha
   mov bx, ax   ; off to bx
   mov es, dx
   mov ax, [es:bx]
   popa
   ret

; takes SEG:OFF in DX:AX
; takes data in    BX
set_mem:
   pusha
   mov bx, ax   ; off to bx
   mov es, dx
   mov [es:bx], ax
   popa
   ret


Here's how I am testing it:
There should be a word (0x3456) written at 0x0570. After reading the same memory location, function print_hex16 (input in AX) prints 0x0070, the value that was written to AX before the call to get_mem.
Code:
   mov dx, 0x0050
   mov ax, 0x0070
   mov bx, 0x3456
   call set_mem

   mov dx, 0x0050
   mov ax, 0x0070
   call get_mem
   
   mov bx, 0x07   ; default attribute
   call print_hex16


Thanks for reading and maybe answering...
sdose


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 8:37 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 1054
Your get_mem function doesn't work because PUSHA and POPA save and restore AX, which means your return value gets overwritten by POPA. You're also not saving/restoring ES, which will affect string instructions.

Your set_mem function doesn't work because you overwrite the value you're going to write to memory with the offset.


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 8:40 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 27, 2004 11:00 pm
Posts: 814
Location: CA
the most obvious problem I see is that pusha/popa surrounding the function... do you understand what those instructions do?

if you examine the function and think about what those functions do, it should be obvious what your problem is


however, both your functions fail to return ES to its previous state (perhaps that is intentional, but in case its not, be aware of it -- note your compiler will likely assume that ES was unmodified)

also the C version only works if DS.base==SS.base... while this is true for most PMode C platforms, this could be a problem (this can be fixed either by removing the mov bx,sp line and using sp offsets in the rest of the lines, or (more traditionally) changing it to mov bp, sp, and changing the remaining offsets to bp rather than bx)

_________________
## ---- ----- ------ Intel Manuals
OSdev wiki


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 8:54 am 
Offline
User avatar

Joined: Wed Nov 02, 2016 2:20 am
Posts: 6
Oh thank you guys!

I know what these do, but it seems I was confused with pushing and popping, saving context...

The C code was written for 16bit real mode .com-files with a single segment for all. So i assume it is correct, what i have there...

Now it is working:
Code:
; get a 16bit word from an absolute location in SEG:OFF format
; takes SEG:OFF in DX:AX
; returns data in  AX
get_mem:
   push es
   mov bx, ax      ; off to bx
   mov es, dx      ; segment
   mov ax, [es:bx]
   pop es
   ret

; takes SEG:OFF in DX:AX
; takes data in    BX
set_mem:
   push es
   push bx         ; save data
   mov bx, ax      ; off to bx
   mov es, dx      ; segment
   pop ax         ; get back data
   mov [es:bx], ax
   pop es
   ret


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 9:05 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 1054
Now both of your functions clobber BX. I don't know what calling conventions you're using, but if that's a problem, you'll need to change it.

Is there any reason you didn't use xchg to swap the contents of AX and BX in your set_mem function?


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 9:15 am 
Offline
User avatar

Joined: Wed Nov 02, 2016 2:20 am
Posts: 6
I'm doing this in assembler only, so there are no calling conventions i have to use.

There is no particular reason for not using xchg. I simply didn't know i about it, when i wrote this first time.

Is it already available on 80186? Is there any list, that shows which generation introduced which opcode?


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 9:28 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 1054
sdose wrote:
I'm doing this in assembler only, so there are no calling conventions i have to use.

In that case, you don't have to push/pop ES either, unless you really want to.

sdose wrote:
Is it already available on 80186? Is there any list, that shows which generation introduced which opcode?

It's available on all x86 CPUs, including the 8086 and 8088. There are some nice lists here that include information on the minimum CPU requirements for each instruction.


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 9:31 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7897
Location: At his keyboard!
Hi,

sdose wrote:
Now it is working:


That is unfortunate - the code is so inefficient that it would be better if it didn't work.

In general; when something is mostly just a single instruction it should never be a function/routine; because a function/routine adds the overhead of a call/return plus the overhead of moving things around (to get input and output parameters in the expected places) plus the overhead of saving/restoring registers; and because a function/routine makes it harder to maintain the code (e.g. having to try to remember if "mov dx,0x50" is for the "segment parameter" or for the "offset parameter" or for something else); and because a function/routine makes it impossible to optimise the code (e.g. when 2 function calls end up using the same segment it makes it impossible to remove the unnecessary second segment load).

Consider something a little more like this:

Code:
   mov ax,0x0050
   mov fs,ax

   mov word [fs:0x0070],0x3456

   mov ax,[fs:0x0070]
   
   mov bx, 0x07   ; default attribute
   call print_hex16



Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 1:59 pm 
Offline
User avatar

Joined: Wed Nov 02, 2016 2:20 am
Posts: 6
Brendan wrote:
In general; when something is mostly just a single instruction it should never be a function/routine;

I've seperated it, because i need this function in a few places and it still is much easier for me to understand my assembly code, if i have everything seperated and named.

Quote:
because a function/routine adds the overhead of a call/return plus the overhead of moving things around (to get input and output parameters in the expected places) plus the overhead of saving/restoring registers;

I need this one in first place for accessing the IVT on boot, so it is not critical as it comes to speed.
Quote:
and because a function/routine makes it harder to maintain the code (e.g. having to try to remember if "mov dx,0x50" is for the "segment parameter" or for the "offset parameter" or for something else);

As far as i can tell, it looks like DX:AX is a semi-standard on giving address in SEG:OFF format and for 32bit data. I'm using this in all my functions, that are working with SEG:OFF or 32bit data.

Having xchg in mind and your fs-driven solution, I think i can optimize it a bit, but i really want to keep it in seperated functions.
As it will be used in different places, i think it is quite handy, regardless the speed-loss of context saving/restoring. I don't have to take care of the context, and always the same function used for the (more or less) same thing.


Top
 Profile  
 
 Post subject: Re: Problems with segmenting and nasm
PostPosted: Wed Dec 21, 2016 2:42 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7897
Location: At his keyboard!
Hi,

sdose wrote:
Brendan wrote:
In general; when something is mostly just a single instruction it should never be a function/routine;

I've seperated it, because i need this function in a few places and it still is much easier for me to understand my assembly code, if i have everything seperated and named.


In that case, why not write functions to avoid using all of the other instructions too? That way, instead of doing something simple like (e.g) "add ax,bx" you could turn it into a bloated and unmaintainable mess in the hope of avoiding becoming familiar with assembly language programming... :roll:

sdose wrote:
Quote:
because a function/routine adds the overhead of a call/return plus the overhead of moving things around (to get input and output parameters in the expected places) plus the overhead of saving/restoring registers;

I need this one in first place for accessing the IVT on boot, so it is not critical as it comes to speed.


For boot code; I'd recommend setting all segment registers (CS, SS, DS and ES) to 0x0000 and leaving them like that unless you have to access something outside the first 64 KiB; partly because it makes things so much easier (especially if/when you're switching to/from protected mode to copy data from disk to above 0x000100000, access ACPI tables, clear video card's linear frame buffer, etc).

sdose wrote:
Quote:
and because a function/routine makes it harder to maintain the code (e.g. having to try to remember if "mov dx,0x50" is for the "segment parameter" or for the "offset parameter" or for something else);

As far as i can tell, it looks like DX:AX is a semi-standard on giving address in SEG:OFF format and for 32bit data. I'm using this in all my functions, that are working with SEG:OFF or 32bit data.


DX:AX is relatively common for 32-bit integers in 16-bit code (and EDX:EAX for 64-bit integers in 32-bit code), mostly because that's what the CPU expects for unsigned multiplication and division (the registers used by "MUL" and "DIV" instructions). The "standard" for SEG:OFF is to use a segment register (e.g. "DS:SI" and "ES:DI" are the most common, mostly because of the CPU's string instructions).

sdose wrote:
Having xchg in mind and your fs-driven solution, I think i can optimize it a bit, but i really want to keep it in seperated functions.
As it will be used in different places, i think it is quite handy, regardless the speed-loss of context saving/restoring. I don't have to take care of the context, and always the same function used for the (more or less) same thing.


As it will be used in different places (and not just for accessing the firmware's IVT); don't forget that "xchg" (when an operand is a memory access) has an implied "lock" (for multi-CPU consistency) which can make it much slower than a pair of "mov" instructions.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 3 guests


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 post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group