vitsoft wrote: 23 Oct 2025 20:08
Currently I'm finishing a new version of €ASM but SEH will not be in it yet, I'm sorry.
Thank you for the quick response!
Just to clarify — no, no, I'm not asking for SEH to be implemented in EuroAssembler at all. That would be overengineering, and SEH is handled differently on different platforms.
However, it would be great to have the ability to handle relative addresses with lower bit-widths.
The trick of setting the handler address at run-time works for the unwind structure, but unfortunately not for the exception data structure, since it's part of the PE header and must be defined at "compile" time.
In general, SEH works in a relatively straightforward way. Here's the documentation -
https://learn.microsoft.com/en-us/cpp/b ... w=msvc-170.
There are three 32-bit fields in .pdata section:
| ULONG | Function start address (begin of "critical" section)
| ULONG | Function end address (end of "critical" section)
| ULONG | Unwind info address (where address of the handler stored)
All three addresses are image-relative, meaning they are 32-bit offsets from the base address of the image containing the function table entry.
And yes, even in 64-bit applications, these fields are 32-bit.
Physically they written in executable at offset 0x800
0x0000000800: 18 10 00 00 1F 10 00 00 44 20 00 00 ...
And EuroAssembler did this correctly in [.pdata] SEGMENT PURPOSE=EXCEPTION
But unfortunately DD handler - %^IMAGEBASE is not allowed, that the problem.
Basically, if I try to assign a value that doesn't fit the specified data type, EuroAssembler correctly raises an error. For example:
DD 0x100000000 ; -> E6729 Data value "0x100000000" is too big for datatype "D".
However, if I try something like:
DD handler - %^IMAGEBASE
Then I get one warning and one error:
W3529 64bit symbol does not match datatype "D".
E6729 Data value "handler - 4194304" is too big for datatype "D".
This happens because the EuroAssembler checks the data types, but not the actual computed values behind. While it's true that subtracting two 64-bit values *might* result in a value that doesn't fit into 32 bits, in this specific case, the result of `handler - %^IMAGEBASE` is only `0x10B5` (4277 decimal), which clearly fits.
So, I'm suggesting to add some "intelligence" to this check — allow `DD` when the computed value fits, even if the operands are 64-bit.
By the way, `DW` would also work here, but obviously not `DB`:
DB handler - %^IMAGEBASE
This correctly should raise error something like this:
E6729 Data value "handler - 4194304" (4277) is too big for datatype "B".
Since the handler address is known at compile time and everything is static, I’m asking for the EuroAssembler to evaluate the expression and raise errors based on the *actual value*, not just the operand types, this will allow to fill Exception data structure correctly.
Small code snippet:
EUROASM AutoSegment=Yes, CPU=X64, SIMD=AVX2
%^SourceName PROGRAM Format=PE, Width=64, Model=Flat, IconFile=, Entry=Start
INCLUDE winscon.htm, winabi.htm, cpuext64.htm
handlerAdr D "Address of handler is 0x",0
handlerRva D "RVA Address of handler is 0x",0
Buf DB 8 * B
DQ handler - %^IMAGEBASE ; This is OK, but too wide for SEH purposes
DD handler - %^IMAGEBASE ; This is needed, but unfortunately is not allowed:
;W3529 64bit symbol does not match datatype "D".
;E6729 Data value "handler - 4194304" is too big for datatype "D".
; But Data value "handler - 4194304" is 0x000010B5 - its FIT into "D"
Start:nop
MOV RAX, handler ; Address
StoH Buf
StdOutput handlerAdr, Buf, Eol=Yes, Console=Yes
MOV RAX, handler - %^IMAGEBASE ; RVA
StoH Buf
StdOutput handlerRva, Buf, Eol=Yes, Console=Yes
TerminateProgram
handler:
nop ; just dummy
retn
ENDPROGRAM
Output:
>rvademo.exe
Address of handler is 0x004010B5
RVA Address of handler is 0x000010B5
And, by the way, this is allowed in EuroAssembler and handled correctly:
MOV EAX, handler - %^IMAGEBASE ; RVA as 32-bit
StoH Buf32
StdOutput handlerRva, Buf32, Eol=Yes, Console=Yes
So, in theory should be possible also in DD handler - %^IMAGEBASE form.
--- UPDATE ---
Just got it running with OFFSET#
minimal code:
EUROASM CPU=X64, SIMD=AVX2
%^SourceName PROGRAM Format=PE, Width=64, Model=Flat, IconFile=, Entry=Start
INCLUDE winscon.htm, winabi.htm, cpuext64.htm
[.text]
Start:nop
StdOutput helloMsg, Eol=Yes, Console=Yes
try:
MOV ECX,0x40000000 ; Instructions Counter
RDPMC ; EXCEPTION_PRIV_INSTRUCTION (0xC0000096)
safe_place:
StdOutput finishMsg, Eol=Yes, Console=Yes
TerminateProgram
handler:
SUB RSP,8*(4+1) ; 0x0F8 is offset to CONTEXT64.Rip
mov [R8+0x0F8], safe_place, DATA=Q ; safe_place = 0x40101F
StdOutput exceptionMsg, Eol=Yes, Console=Yes
XOR EAX,EAX
ADD RSP,8*(4+1)
retn
[.data]
helloMsg D "Hello, SEH!",0
finishMsg D "Sucessfully finished",0
exceptionMsg D "Instruction caused exception",0
align 4 ; The RUNTIME_FUNCTION structure must be DWORD aligned
UNWIND DB 0x19,0,0,0 ; Version & Flags hard coded for the moment
DD (OFFSET# handler) + 0x1000
[.pdata] SEGMENT PURPOSE=EXCEPTION
DD (OFFSET# try) + 0x1000
DD (OFFSET# safe_place) + 0x1000
DD (OFFSET# UNWIND) + 0x2000 ; virtual address of .data is 0x2000
ENDPROGRAM
and result:
>seh4.exe
Hello, SEH!
Instruction caused exception
Sucessfully finished
But the OFFSET# is not RVA, so I have to add 0x1000 (and 0x2000 for UNWIND_INFO).
May be something like RVA#:
DD RVA# try
DD RVA# safe_place
DD RVA# UNWIND ; virtual address of .data, set correct
which will act exactly the same as <address> - %^IMAGEBASE and be more elegant, because hard coded 0x1000 and 0x2000 are not good idea.