flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Executing programs more than 64k

Author
Thread Post new topic Reply to topic
me239



Joined: 06 Jan 2011
Posts: 200
me239
Hello everyone! I was just working some more on my xOS until I ran into a problem. Some of my programs with embedded bitmaps cannot display because they are > 64k. MS-DOS 6.22 could do it, but mine can't. How can I fix this?
Post 12 Jul 2011, 21:11
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa
You need to page them when you load them. 64K at a time in each segment, contiguously. Then create a base pointer and a count. Create read and write functions that are aware of this layout. You can also put them higher in memory by going in and out of PM mode.
Post 13 Jul 2011, 00:24
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
garystampa wrote:
You need to page them when you load them. 64K at a time in each segment, contiguously. Then create a base pointer and a count. Create read and write functions that are aware of this layout. You can also put them higher in memory by going in and out of PM mode.
Can you provide code on how this is done? Also my code is Realmode if you haven't guessed.
Post 13 Jul 2011, 03:41
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
If you seperate code/data/stack then each can be 64kb.
This is most simple and common approach.
For >64kb code it need to be setup dynamically.
Would your program fit into 3 segments like so?
Post 13 Jul 2011, 04:31
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
bitshifter wrote:
If you seperate code/data/stack then each can be 64kb.
This is most simple and common approach.
For >64kb code it need to be setup dynamically.
Would your program fit into 3 segments like so?
I'm trying to follow what you are saying. So if I separate all parts of an executable (code/data/stack), I can execute files >64k how? My OS can run EXE's if that's any help since I know EXE's set up there own stack.
Post 13 Jul 2011, 07:23
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa
I misunderstood what you're doing. So your EXE's are large because you've embedded BMPs in them?

Not sure what sort of EXE header you have, but there's a fix-up table in most EXE headers that points at the various segments and their offset within the EXE. You then layout the memory image and punch the true values into those locations.

But since I don't know your EXE header or your OS's EXE loader I can't really tell you anymore.
Post 13 Jul 2011, 13:08
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
garystampa wrote:
I misunderstood what you're doing. So your EXE's are large because you've embedded BMPs in them?

Not sure what sort of EXE header you have, but there's a fix-up table in most EXE headers that points at the various segments and their offset within the EXE. You then layout the memory image and punch the true values into those locations.

But since I don't know your EXE header or your OS's EXE loader I can't really tell you anymore.
I was actually talking about my COM files, but suggesting EXE's as a fix. BTW, my EXE's are standard DOS MZ executables and my loader is identical to Bootprog's. EDIT: I realize that COM files must be below 64k, but how does MS-DOS still support them?
Post 13 Jul 2011, 16:24
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa
They don't *have* to be 64K. They can allocate pointers and consume all available memory. The real difference is the loader: a com file is an exact image of the file as it lays out in memory and is restricted to a single 64k segment, whereas an exe has relocatable "pages" and is only restricted to available memory.

Often loaders don't actually relocate they tend to lay contiguously. All DOS exe headers have a fix-up table. This effectively tells you how many segments there are and what they're offsets (with respect to one another) should be. I'm not saying it right - it's actually pretty simple to walk through the header and poke the values into the memory where the exe is loaded.

Also in DOS, uninitialized data is usually allocated by the start-up routine and then cleared to 0. Unlike a com, there's no disk space wasted with it.
Post 13 Jul 2011, 19:52
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
garystampa wrote:
They don't *have* to be 64K. They can allocate pointers and consume all available memory. The real difference is the loader: a com file is an exact image of the file as it lays out in memory and is restricted to a single 64k segment, whereas an exe has relocatable "pages" and is only restricted to available memory.

Often loaders don't actually relocate they tend to lay contiguously. All DOS exe headers have a fix-up table. This effectively tells you how many segments there are and what they're offsets (with respect to one another) should be. I'm not saying it right - it's actually pretty simple to walk through the header and poke the values into the memory where the exe is loaded.

Also in DOS, uninitialized data is usually allocated by the start-up routine and then cleared to 0. Unlike a com, there's no disk space wasted with it.
I just tried to run a simple EXE with segmented sections, but it failed. Can you tell me why?
EXE code:
Code:
format MZ
entry main:start
stack 100h
segment main
start:
        mov     ax, text
        mov     ds, ax
        mov     dx, hello
        call    extra:write
        int     20h
segment text
 hello db 'Hello World!', 0 ; NULL terminated
segment extra
 write:
        mov ah, 3 ; my write function
        int 21h
        retf
    

My EXE loader code
Code:
    mov     ax, word[cs:loadseg]
    mov     ds, ax
      add     ax, [ds:08h]                ; ax = image base
   mov     cx, [ds:06h]                ; cx = reloc items
  mov     bx, [ds:18h]                ; bx = reloc table pointer
  jcxz    RelocationDone
ReloCycle:
    mov     di, [ds:bx]         ; di = item ofs
     mov     dx, [ds:bx+2]               ; dx = item seg (rel)
       add     dx, ax                  ; dx = item seg (abs)
       push    ds
  mov     ds, dx                  ; ds = dx
   add     [ds:di], ax         ; fixup
     pop     ds
  add     bx, 4                   ; point to next entry
       loop    ReloCycle
RelocationDone:
    mov     bx, ax
      add     bx, [ds:0Eh]
    mov     ss, bx                  ; ss for EXE
        mov     sp, [ds:10h]                ; sp for EXE
        add     ax, [ds:16h]                ; cs
        push    ax
  push    word [ds:14h]               ; ip
Run:
    sti
 retf
    

printing code
Code:
int21_03:
       call    printf
      popf
        iret
printf:
        lodsb
        cmp al, 0
        jz @f
        mov ah, 0eh
        int 10h
        jmp printf
@@:
        ret
    
Post 13 Jul 2011, 20:40
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa
In the printing code: why are you popping the flags and issuing an iret? Usually it's either: popf, retf OR iret.
Post 14 Jul 2011, 12:25
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa
I haven't built an EXE loader in many years. You've got the right idea, but I think you need to make sure your pointers are adding up correctly.

I can't see where the EXE is - I assumed you loaded it contiguously from the DS address.

Also - you can ES instead of pushing and popping DS, and I don't think you want to add to the item, I think you want to mov to it. (as I remember, the location should have a 0 in it.) If you use ES:DI you can just use stosw.

Debug the reloc code and before you pop the value in, disassemble the address pointed to by DS:DI minus a couple of bytes. You should see a decode for a mov reg,0000 and then mov segreg,reg. The DS:DI pointer should point at the 0000.

Depending on compilers and other EXE creators - making the stack in an area other than the DS can have bad results. Many small-model EXE's expect the stack to be inside the data segment and pass everything as 16-bit - assumes the SS and DS are equal. So have a look how/why/where you're creating the stack too.
Post 14 Jul 2011, 12:56
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
garystampa wrote:
I haven't built an EXE loader in many years. You've got the right idea, but I think you need to make sure your pointers are adding up correctly.

I can't see where the EXE is - I assumed you loaded it contiguously from the DS address.

Also - you can ES instead of pushing and popping DS, and I don't think you want to add to the item, I think you want to mov to it. (as I remember, the location should have a 0 in it.) If you use ES:DI you can just use stosw.

Debug the reloc code and before you pop the value in, disassemble the address pointed to by DS:DI minus a couple of bytes. You should see a decode for a mov reg,0000 and then mov segreg,reg. The DS:DI pointer should point at the 0000.

Depending on compilers and other EXE creators - making the stack in an area other than the DS can have bad results. Many small-model EXE's expect the stack to be inside the data segment and pass everything as 16-bit - assumes the SS and DS are equal. So have a look how/why/where you're creating the stack too.
I took your advice to replace the [DS:DI] with the ES stosw code and it worked fine. I don't actually know too much about EXE's as I used to so any help would be appreciated. EDIT: When I said it worked fine, I meant it works the same. The other EXE will still not execute!
Post 15 Jul 2011, 03:32
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
UPDATE! I got it working! turns out STOSW doesn't work because you have to add to DI, not move to it.
Post 15 Jul 2011, 05:45
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa
Actually, that doesn't really make any sense that that "fixed it". Besides, I didn't say move to di, I said if you use es:di, as a pair you can use stosw. I was just trying to suggest reducing instructions, it had nothing to do with how it was working.
Post 15 Jul 2011, 21:58
View user's profile Send private message Reply with quote
me239



Joined: 06 Jan 2011
Posts: 200
me239
garystampa wrote:
Actually, that doesn't really make any sense that that "fixed it". Besides, I didn't say move to di, I said if you use es:di, as a pair you can use stosw. I was just trying to suggest reducing instructions, it had nothing to do with how it was working.
Where do you suggest the STOSW should go? The ADD [ds:di], ax added to the value at DI where STOSW simply replaces the value at DI and increments the register.
Post 16 Jul 2011, 05:43
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-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.