Message board for the users of flat assembler.
> Main > FASMLIB tutorial part 4 - Error Handling
vid 10 Sep 2006, 20:37
before reading this chapter, i suggest you to browse doc/general.txt from latest fasmlib package.
Up to now we didn't discuss error handling any deeper. We just jumped to some "error" label which just displayed some fixed error message. Of course FASMLIB gives you a (little) more than this.
Everytime when FASMLIB function return with CF=1, it also sets EAX to hold error code. Each error code has upcase name prefixed with ERR_, for example ERR_INVALID_HANDLE.
This error code is not just some number, like in most languages, but it is also pointer to corresponding error description. So in fact, we can define error code like this:
ERR_INVALID_HANDLE db "Invalid handle",0
so after error is returned, you can just output string pointed by EAX. Here is example from tutorial part 2, with error message output added:
(we are using stream.write mentioned in tutorial part 3 second post)
format PE console include "%FASMINC%/win32axp.inc" SYSTEM equ win32 include "fasmlib/fasmlib.inc" include "fasmlib/process.inc" include "fasmlib/mem.inc" include "fasmlib/str.inc" include "fasmlib/stream.inc" .code start: ;initialize modules call mem.init jc error call str.init jc error call stream.init jc error ;display _string push dword _string push [stream.stdout] call stream.write jc error ;uninitialize modules call stream.uninit jc error call str.uninit jc error call mem.uninit jc error ;exit process push dword 0 call exit error: ;save error code in EBX mov ebx,eax ;try to write error message to stderr push _error push [stream.stderr] call stream.write ;display error message push ebx push [stream.stderr] call stream.write ;display end of line push _eol push [stream.stderr] call stream.write ;try to uninitialize what we can, without further error checking call stream.uninit call str.uninit call mem.uninit ;exit with code 1 push dword 1 call exit .data _error db "Error: ",0 _string db "Hell o' world",0 _eol db 13,10,0 IncludeIData IncludeUData .end start
Note that most procedures from modules that need initialization can return ERR_MODULE_NOT_INITIALIZED, when module is not initialized. These are not mentioned in documentation.
Note that platform-specific procedures always can return ERR_UNKNOWN. See doc/general.txt for explaination of what is platform-specific procedure. See documentation of procedure see if it is platform specific, every such has a note that it is platform-specific. For this reason, ERR_UNKNOWN is not mentioned in documentation.
This means that altough some procedure says "error: none" in documentation, it can still return these two errors, on given cases.
All other errors are mentioned in documentation. But be aware that more errors can be returned in future versions, so when going to newer release of FASMLIB with your project, carefully read whatsnew.txt.
That is, in fact, all we need for error handling. If you handle error somehow, or want to just ignore it, you can just throw away value in EAX, you don't need to do anything else.
|10 Sep 2006, 20:37||
RedGhost 12 Sep 2006, 23:45
It's good to have a solid error handling system. Personally I usually don't check for errors and when I do it's sloppy, I have terrible programming practice
|12 Sep 2006, 23:45||
vid 13 Sep 2006, 06:31
yup, in FASM you just have to add "jc error" for at least some error handling... it's still better to exit with leaks than to crash.
i was even thinking about some try-catch macros, where you wouldn't even have to write those "jc"s, but i am not sure if it is a good idea. It would be possible with minimal instructions overhead, like:
try libcall func1, [a], b, eax libcall func2, 123 ... catch ERR_FILE_NOT_FOUND: jmp retry catch: ;catch all others push eax libcall stream.write, "error:" pop eax libcall stream.write, [eax] libcall exit, 0
sorry about using libcall macro in this example, it is not explained in tutorials yet (next part will cover it... maybe), i am lazy to write pure code now
resultine code would be something like this:
;libcall func1, [a], b, eax push eax push b push [a] call func1 jc ..catch ;libcall func2, 123 push 123 call func2 jc ..catch ... ..catch_ERR_FILE_NOT_FOUND: cmp eax, ERR_FILE_NOT_FOUND jne ..catch_all jmp retry ;catch: ..catch_all: etc...
it would be neatly possible, but i am afraid that people will get bad practice with ignoring error handling (you know ) with this.
maybe very later
|13 Sep 2006, 06:31||
ChrisLeslie 14 Sep 2006, 07:46
My approach to error handling has been to simply write a message to std out with premature exit upon an error for all library procedures, or macros, that require them. Essentially, string routines than may violate the string boundary as well as disk access. This requires decent error catching code in the procedures. Without such an approach I fear that I would be forever chasing bugs and mysterious crashes. For me, console messages are an indispensible diagnostic and debuging tool.
|14 Sep 2006, 07:46||
vid 14 Sep 2006, 10:30
why not? fasm allows this too. and by the way, in examples contained in tutorial, error handling is just what you described.
here is simple trace what happens after an error:
- FASMLIB routine calls system
- returns with error
- system error code is translated to fasm error code / error message pointer
- fasmlib routine returns to caller with this error
and caller then can (like in my examples):
- notices error happened
- jumps to some "error:" label common for all errors
- displays error (calls str.ptr, str.len, str.writebuf)
... easy ...
|14 Sep 2006, 10:30||
< Last Thread | Next Thread >
Copyright © 1999-2023, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.