flat assembler
Message board for the users of flat assembler.
Index
> Compiler Internals > [SOLVED] kolibri(menuet) port: error handling trashes retadr Goto page 1, 2 Next |
Author |
|
ProMiNick 27 Apr 2020, 03:11
sources https://yadi.sk/d/HTs1wxZvp6BmYw
in case of UI all works properly, in case of succesful compilation all OK too. but in case when fasm should display error page fault happend in code (ASSEMBLE.INC) Code: show_display_buffer: mov eax,[tagged_blocks] or eax,eax jz display_done mov esi,[labels_list] cmp esi,eax je display_done display_messages: sub esi,8 mov eax,[esi+4] ; PROGRAM CRASHED HERE mov ecx,[esi] sub esi,ecx cmp eax,10h je write_addressing_space test eax,eax jnz skip_block push esi call display_block pop esi skip_block: cmp esi,[tagged_blocks] jne display_messages display_done: ret registers at crash eax = $0c3e34d8 (points to undefined area) ebx = 0 ecx = $27000 (points to undefined area) edx = $27000 (points to undefined area) esi = $0c3e3738 (points to undefined area) ebp = 0 esp = $20FE8 (stack content: $00000ce9,$00000d4e,$0001a348,$00004F20,$0000083A,$000002FE,undefined eip = $5bd8 eflags = $1212 in proper case instead of crash should be output (in test case was that error): Code: flat assembler version 1.73.23 example.asm [36]: mow eax, 10 ; function 10 : wait until event error: illegal instruction crash happend indefinitely from error type (absence of source or whatever) and always at display_messages. Tomasz, I understand that thour code correct. and bug somewhere in interface I produced. But, can thou help where I could make mistake? thanks. _________________ I don`t like to refer by "you" to one person. My soul requires acronim "thou" instead. Last edited by ProMiNick on 27 Apr 2020, 16:14; edited 1 time in total |
|||
27 Apr 2020, 03:11 |
|
ProMiNick 27 Apr 2020, 09:11
display itself work correct:
file with content display 'hello world' db 0 compiled succesfuly and hello world displayed even display with up to 1kb string to display displayed OK. something interfered to display only at error handling |
|||
27 Apr 2020, 09:11 |
|
Tomasz Grysztar 27 Apr 2020, 09:21
My question was concerning the "display_block" function as defined by the interface. Please try reducing it to just a RETN as see if that changes anything.
And the second question was whether an error on a single-line source also causes a crash. |
|||
27 Apr 2020, 09:21 |
|
ProMiNick 27 Apr 2020, 10:52
I shrinked display_block to RETN.
Error still same. But I see program succeed to show Code: flat assembler version 1.73.23 example.asm [36]: [ error: illegal instruction in case of 1 line source I see Code: flat assembler version 1.73.23 example.asm [1]: [ error: illegal instruction |
|||
27 Apr 2020, 10:52 |
|
Tomasz Grysztar 27 Apr 2020, 11:06
Since the entire error message is generated and shown, it seems that the program makes it to "jmp exit_program" at the end of "assembler_error" handling - and yet it still somehow lands inside the "show_display_buffer" code later? Please try debugging what happens at the "exit_program" point.
|
|||
27 Apr 2020, 11:06 |
|
ProMiNick 27 Apr 2020, 13:44
Is that normal that after exit program illegal instruction caused again?
Code: display_line_data: ... $E56: mov esi,error_suffix ;error_suffix=$1AAE0, content ($2e,0,':',$20,'[') $E5B: call $c88 ; call display_string display_string: $C88: pushad $C89: cmp byte[esi],0 $C8C: jz $C9A $C8E: mov dl,[esi] $C90: call $C07 ;call display_character display_character: $C07: pushad $C08: cmp dword[$1AAC2],8 ; there 8 $C0F: jnz $C78 $C11: cmp dl,$D ;there $2e $C14: jz $C2F $C16: cmp dl,$A ;there $2e $C19: jnz $C31 ;$C1B: and dword[$1AACF],$FFFF ;$C25: add dword[$1AACF],$7000A ;$C2F: popad ;$C30: ret $C31: mov eax,[textxy] ;textxy=$1AACF, content $A3005A $C36: cmp ax,[bottom_right] ;bottom_right=$634,content $00CC $C3D: ja $C2F $C3F: shr eax,$10 $C42: cmp ax, [bottom_right+2] ;bottom_right+2=$636,content $105 $C49: ja $C2F $C4B: mov [dc],dl ;dc=$1AAD3 $C51: mov eax,4 ;SF_DRAW_TEXT=4 $C56: mov ebx,[textxy] $C5C: mov ecx,[sc.work_text] ;sc.work_text=$1F444,content 0 $C62: mov edx,dc $C67: xor esi,esi $C69: inc esi $C6A: int $40 $C6C: add [textxy],0x00060000 $C76: popad $C77: ret $C95: add esi,1 $C98: jmp $C89 $C89: cmp byte[esi],0 $C8C: jz $C9A $C9A: popad $C9B: ret $E60: jmp $95C ;exit_program=$95C exit_program: $95C: cmp [_mode],NORMAL_MODE $963: jnz $978 $965: mov eax,$44 ; SF_SYS_MISC $96A: mov ebx,$D ; SSF_MEM_FREE $96F: mov ecx,[memblock] ; memblock=$1E2C8, content $27000 $975: int $40 $977: ret $4F14: jae $4F0F $4F0F: call $50BB $50BB: mov eax,[$1DE54] ; content $0C3C67B4 $50C0: sub eax, $100 $50C5: cmp edi,eax $50C7: ja $E65 $50CD: lodsb $50CE: cmp al,l $50D0: jz $543C $50D6: jb $5479 $50DC: cmp al,3 $50DE: jb $517A $50E4: jz $52C2 $50EA: cmp al,4 $50EC: jz $53D8 $50F2: cmp al,$F $50F4: jz $5113 $50F6: cmp al,$13 $50F8: jz $5108 $50FA: cmp al,$10 $50FC: jnz $F04 ; jnz illegal_instruction illegal_instruction: $F04: push $1A33C ; content 'illegal instruction',0 $F09: jmp $1091 ; jmp error_with_source error_with_source: $1091: cmp dword[$1DDBC],0 ; content 0 $1098: jz $D3D ; jz assembler_error |
|||
27 Apr 2020, 13:44 |
|
Tomasz Grysztar 27 Apr 2020, 13:46
Nothing should be happening after "jmp exit_program", fasm does not expect anything more to happen when it jumps there, it should simply terminate the process.
If it is the RET instruction that is expected to end the process after "exit_program", you may need to restore the original stack frame (see libc version for an example). |
|||
27 Apr 2020, 13:46 |
|
ProMiNick 27 Apr 2020, 14:00
so, I understand why error caused again, I expect that in stack ret address to message processing - but there are retaddr of error handling.
how to fix that? I cant fix it in system.inc - without error handling stack restored correctly. I cant fix it in error.inc - it shoudnt affect other fasm variant. so I shoud provide 2 different program exits. Or check at exit errorflag and process stack accordig to it. Last edited by ProMiNick on 27 Apr 2020, 14:27; edited 1 time in total |
|||
27 Apr 2020, 14:00 |
|
Tomasz Grysztar 27 Apr 2020, 14:08
This is all up to the interface implementation, the fasm's core does not need to know anything about that. It jumps to "exit_program" when it is finished, but because this state may be achieved through a jump from deep withing call stack, the ESP is not the same as it was when assembler core was started. Therefore if you want to be able to use the RET instruction there, you need to restore your old ESP first.
|
|||
27 Apr 2020, 14:08 |
|
ProMiNick 27 Apr 2020, 14:33
I should store stack value for restoring in global variable?
Or there any error_flag that I could check at exit_process and if error handling shift stack top always on fixed value I could restore it via add esp,that value |
|||
27 Apr 2020, 14:33 |
|
ProMiNick 27 Apr 2020, 16:11
Thanks for help Tomasz.
https://yadi.sk/d/HTs1wxZvp6BmYw - I update source for kolibri. |
|||
27 Apr 2020, 16:11 |
|
Tomasz Grysztar 27 Apr 2020, 16:39
BTW, do you plan to port fasmg too? It uses very similar interfaces (although more polished), but also requires a malloc/realloc implementation (if OS does not provide one). I currently only have an implementation for x64 version, but I could prepare a similar one for 32-bit OSes if needed (I did in fact consider making a simple 32-bit malloc for the purpose of DOS version, but it never really felt needed, since I use Win32 version with HX under DOS anyway).
|
|||
27 Apr 2020, 16:39 |
|
ProMiNick 27 Apr 2020, 16:53
That would be nice too.
|
|||
27 Apr 2020, 16:53 |
|
Tomasz Grysztar 29 Apr 2020, 12:41
All right, I have prepared the most basic implementation of malloc/realloc. It is really straightforward and almost minimalistic, yet it still seems to works decently with fasmg.
This code is going to be a part of the fasmg's source base, therefore fasmg's license applies: Code: ; a very basic implementation of malloc/realloc ; for porting fasmg to systems that do not have such API natively struct MemoryHeader size dd ? ; total size of this block, the lowest bit set for blocks in use preceding_size dd ? ; total size of the block that precedes this one in memory (zero if this is an initial block of address range) ends struct FreeMemory header MemoryHeader right dd ? ; next free block in cyclic list left dd ? ; previous free block in cyclic list ends VALLOC_MIN = 100000h valloc: ; in: ecx = requested minimum size ; out: eax - allocated block, ecx = allocated size, zero if failed ; preserves: ebx, esi, edi ; note: ; this function requests raw memory from the OS; ; it may allocate much more memory than requested (even entire available memory), ; the obtained memory is kept indefinitely in the pool for malloc ; and should be released by OS automatically when the process ends; ; if the OS does not do it automatically, additional list of the memory areas ; may need to be maintained to release them before exit cmp ecx,VALLOC_MIN jbe valloc_size_minimum dec ecx and ecx,(-1) shl 12 add ecx,1 shl 12 jmp valloc_size_ready valloc_size_minimum: mov ecx,VALLOC_MIN valloc_size_ready: push ecx invoke VirtualAlloc,0,ecx,MEM_COMMIT,PAGE_READWRITE pop ecx test eax,eax jz valloc_failed retn valloc_failed: xor ecx,ecx retn malloc: malloc_fixed: malloc_growable: ; in: ecx = requested size ; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return) ; preserves: ebx, esi, edi dec ecx and ecx,(-1) shl 2 add ecx,1 shl 2 jc out_of_memory add ecx,sizeof.MemoryHeader jc out_of_memory cmp ecx,sizeof.FreeMemory jae malloc_size_ok mov ecx,sizeof.FreeMemory malloc_size_ok: mov eax,[malloc_freelist] test eax,eax jz malloc_new find_fit: cmp ecx,[eax+MemoryHeader.size] jbe malloc_use_block mov eax,[eax+FreeMemory.left] cmp eax,[malloc_freelist] jne find_fit malloc_new: push ecx add ecx,sizeof.MemoryHeader jc out_of_memory call valloc test ecx,ecx jz out_of_memory xor edx,edx mov [eax+MemoryHeader.preceding_size],edx pop edx push eax sub ecx,edx cmp ecx,sizeof.FreeMemory+sizeof.MemoryHeader jb no_space_for_free_block mov [eax+MemoryHeader.size],edx add eax,edx mov [eax+MemoryHeader.preceding_size],edx mov edx,ecx sub edx,sizeof.MemoryHeader dec edx and edx,(-1) shl 2 add edx,1 shl 2 mov [eax+MemoryHeader.size],edx mov ecx,[malloc_freelist] jecxz freelist_empty mov [eax+FreeMemory.left],ecx mov edx,eax xchg edx,[ecx+FreeMemory.right] mov [eax+FreeMemory.right],edx mov [edx+FreeMemory.left],eax mov edx,[eax+MemoryHeader.size] jmp free_block_ready no_space_for_free_block: sub ecx,sizeof.MemoryHeader add edx,ecx mov [eax+MemoryHeader.size],edx jmp append_limiter freelist_empty: mov [eax+FreeMemory.left],eax mov [eax+FreeMemory.right],eax free_block_ready: mov [malloc_freelist],eax append_limiter: add eax,edx mov [eax+MemoryHeader.preceding_size],edx mov [eax+MemoryHeader.size],sizeof.MemoryHeader or 1 ; cannot be freed pop eax finish_malloc: mov ecx,[eax+MemoryHeader.size] or [eax+MemoryHeader.size],1 add eax,sizeof.MemoryHeader sub ecx,sizeof.MemoryHeader retn malloc_use_block: mov edx,[eax+MemoryHeader.size] sub edx,ecx cmp edx,sizeof.FreeMemory jb use_whole_block mov [eax+MemoryHeader.size],ecx mov [eax+ecx+MemoryHeader.preceding_size],ecx add ecx,eax mov [malloc_freelist],ecx mov [ecx+MemoryHeader.size],edx mov [ecx+edx+MemoryHeader.preceding_size],edx mov edx,[eax+FreeMemory.right] cmp edx,eax je update_free_singleton mov [ecx+FreeMemory.right],edx mov [edx+FreeMemory.left],ecx mov edx,[eax+FreeMemory.left] mov [ecx+FreeMemory.left],edx mov [edx+FreeMemory.right],ecx jmp finish_malloc update_free_singleton: mov [ecx+FreeMemory.left],ecx mov [ecx+FreeMemory.right],ecx jmp finish_malloc use_whole_block: mov edx,[eax+FreeMemory.right] cmp edx,eax je depleted_freelist mov ecx,[eax+FreeMemory.left] mov [ecx+FreeMemory.right],edx mov [edx+FreeMemory.left],ecx mov [malloc_freelist],edx jmp finish_malloc depleted_freelist: and [malloc_freelist],0 jmp finish_malloc mfree: ; in: eax - memory block ; out: cf set on error ; preserves: ebx, esi, edi ; note: eax may have value 0 or -1, it should be treated as invalid input then test eax,eax jz mfree_error cmp eax,-1 je mfree_error sub eax,sizeof.MemoryHeader mov ecx,[eax+MemoryHeader.size] btr ecx,0 jnc mfree_error cmp ecx,sizeof.FreeMemory jb mfree_error cmp [eax+ecx+MemoryHeader.preceding_size],ecx jne mfree_error mov [eax+MemoryHeader.size],ecx mov edx,eax sub edx,[eax+MemoryHeader.preceding_size] cmp edx,eax je no_preceding_block test [edx+MemoryHeader.size],1 jz coalesce_with_preceding_block no_preceding_block: test [eax+ecx+MemoryHeader.size],1 jz coalesce_with_following_block mov ecx,[malloc_freelist] jecxz mfree_init_freelist mov edx,[ecx+FreeMemory.right] mov [eax+FreeMemory.left],ecx mov [edx+FreeMemory.left],eax mov [eax+FreeMemory.right],edx mov [ecx+FreeMemory.right],eax mfree_ok: mov [malloc_freelist],eax clc retn mfree_init_freelist: mov [eax+FreeMemory.left],eax mov [eax+FreeMemory.right],eax jmp mfree_ok mfree_error: stc retn coalesce_with_preceding_block: add ecx,[edx+MemoryHeader.size] test [edx+ecx+MemoryHeader.size],1 jz coalesce_on_both_ends mov [edx+MemoryHeader.size],ecx mov [edx+ecx+MemoryHeader.preceding_size],ecx clc retn coalesce_on_both_ends: lea eax,[edx+ecx] add ecx,[eax+MemoryHeader.size] mov [edx+MemoryHeader.size],ecx mov [edx+ecx+MemoryHeader.preceding_size],ecx mov [malloc_freelist],edx mov ecx,[eax+FreeMemory.left] mov edx,[eax+FreeMemory.right] mov [edx+FreeMemory.left],ecx mov [ecx+FreeMemory.right],edx clc retn coalesce_with_following_block: push ebx lea ebx,[eax+ecx] add ecx,[ebx+MemoryHeader.size] mov [eax+MemoryHeader.size],ecx mov [eax+ecx+MemoryHeader.preceding_size],ecx mov ecx,[ebx+FreeMemory.left] mov edx,[ebx+FreeMemory.right] mov [ecx+FreeMemory.right],eax mov [edx+FreeMemory.left],eax mov ecx,[ebx+FreeMemory.left] mov edx,[ebx+FreeMemory.right] mov [eax+FreeMemory.left],ecx mov [eax+FreeMemory.right],edx pop ebx jmp mfree_ok realloc: ; in: eax - memory block, ecx = requested size ; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return) ; preserves: ebx, esi, edi dec ecx and ecx,(-1) shl 2 add ecx,1 shl 2 jc out_of_memory add ecx,sizeof.MemoryHeader jc out_of_memory sub eax,sizeof.MemoryHeader mov edx,[eax+MemoryHeader.size] and edx,not 1 cmp ecx,edx jbe realloc_retain test [eax+edx+MemoryHeader.size],1 jnz realloc_and_copy add edx,[eax+edx+MemoryHeader.size] cmp ecx,edx ja realloc_and_copy sub edx,ecx cmp edx,sizeof.FreeMemory jb append_whole_block push esi edi push ecx edx lea edi,[eax+ecx] xchg ecx,[eax+MemoryHeader.size] and ecx,not 1 lea esi,[eax+ecx] mov ecx,[esi+FreeMemory.left] mov edx,[esi+FreeMemory.right] mov [edx+FreeMemory.left],edi mov [ecx+FreeMemory.right],edi mov ecx,[esi+FreeMemory.left] mov edx,[esi+FreeMemory.right] mov [edi+FreeMemory.left],ecx mov [edi+FreeMemory.right],edx mov [malloc_freelist],edi pop edx ecx mov [edi+MemoryHeader.size],edx mov [edi+edx+MemoryHeader.preceding_size],edx mov [edi+MemoryHeader.preceding_size],ecx pop edi esi jmp finish_malloc append_whole_block: add edx,ecx mov [eax+edx+MemoryHeader.preceding_size],edx xchg edx,[eax+MemoryHeader.size] and edx,not 1 add edx,eax mov ecx,[edx+FreeMemory.left] cmp ecx,edx je depleted_freelist mov edx,[edx+FreeMemory.right] mov [ecx+FreeMemory.right],edx mov [edx+FreeMemory.left],ecx mov [malloc_freelist],ecx jmp finish_malloc realloc_retain: and [eax+MemoryHeader.size],not 1 jmp finish_malloc realloc_and_copy: push esi edi lea esi,[eax+sizeof.MemoryHeader] call malloc_growable push eax ecx mov edi,eax mov eax,esi mov ecx,[esi-sizeof.MemoryHeader+MemoryHeader.size] shr ecx,2 rep movsd call mfree pop ecx eax pop edi esi retn if used mcheck mcheck: pushfd pushad mov eax,[malloc_freelist] test eax,eax jz integrity_verified verify_freelist: mov ebx,eax verify_preceding_blocks: mov ecx,[ebx+MemoryHeader.preceding_size] jecxz preceding_blocks_ok sub ebx,ecx mov edx,[ebx+MemoryHeader.size] and edx,not 1 cmp ecx,edx je verify_preceding_blocks jmp internal_error preceding_blocks_ok: mov ebx,eax verify_following_blocks: mov ecx,[ebx+MemoryHeader.size] and ecx,not 1 cmp ecx,sizeof.MemoryHeader je following_blocks_ok add ebx,ecx cmp ecx,[ebx+MemoryHeader.preceding_size] je verify_following_blocks jmp internal_error following_blocks_ok: mov edx,[eax+FreeMemory.right] cmp eax,[edx+FreeMemory.left] je verify_next jmp internal_error verify_next: mov eax,edx cmp eax,[malloc_freelist] jne verify_freelist integrity_verified: popad popfd retn end if Also, this very basic implementation does not make use of the "malloc_fixed" and "malloc_growable" hints - it would require a much more sophisticated implementation to make a good use of them, and it probably would not make a noticeable difference anyway. These hints are not really utilized in any port of fasmg, I keep them mostly because they slightly improve readability of the code. The "mcheck" function does a quite through integrity check of the heap portions accessible through the list of free blocks. It is an optional sanity check, but the best place to call it is after all blocks have been freed (after the "assembly_shutdown" call). |
|||
29 Apr 2020, 12:41 |
|
ProMiNick 29 Apr 2020, 13:20
Thanks Tomasz.
all fasmpack was with fasm license only. (I am not interested in my own copyright) I add fasmg license to its subfolder licenses. That would be enought? Or add it in file header comment? I would like to think that I develop only preliminary version. And final ones would be accesible in fasmg official package. And mine package would contain only copy of it. So way that fasmg port will not be part of any OS, but downloadable from web within fasmg package. |
|||
29 Apr 2020, 13:20 |
|
Tomasz Grysztar 29 Apr 2020, 13:28
ProMiNick wrote: I add fasmg license to its subfolder licenses. That would be enought? |
|||
29 Apr 2020, 13:28 |
|
ProMiNick 29 Apr 2020, 13:50
https://yadi.sk/d/HTs1wxZvp6BmYw license done
|
|||
29 Apr 2020, 13:50 |
|
Tomasz Grysztar 29 Apr 2020, 17:01
The DPMI-based DOS version is ready: https://github.com/tgrysztar/fasmg/tree/master/core/source/dos
The code of fasmg easily fits into 64K segment, so it might be even possible to add an unreal mode support there, but I'm going to leave that for when I am able to play a bit with my vintage PC. |
|||
29 Apr 2020, 17:01 |
|
ProMiNick 04 May 2020, 07:57
https://yadi.sk/d/HTs1wxZvp6BmYw updated (fasmg kolibri port for now is still inconsistent so uncompilable)
but its system.inc layer is ready. maybe some portions of kolibri fasm port system.inc will migrate too. More important kolibri port of fasm now accept all requirement to fasm (in every environment same source will produce same output) - it is happened because of processing path slashes (that previously absent) & because of correct realization of make_timestamp & separating it from get_tickcount (previousle they was messed). |
|||
04 May 2020, 07:57 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.