strange behavior of the 'module' functionality

Bug reports (if you don't/won't have a Github account)
Post Reply
stefano
Well known member
Posts: 2151
Joined: Mon Jul 16, 2007 7:39 pm

strange behavior of the 'module' functionality

Post by stefano »

I have few detail at the moment but the current z88dk version seems to encounter problems with the module functionality ('%' operator).

Code just becomes unstable and application crashes, try computing, say, 'srand()%5'.


The ZX Spectrum target shows also the following warning:
Warning at file 'crt0/l_div.asm' line 66: integer '4295038788' out of range
stefano
Well known member
Posts: 2151
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Problem is still in, it seems to have to do with l_div / l_div_u in general, could it be connected to the new z80asm expression evaluation logics ?

XLIB l_div_u
XDEF L_DIVENTRY

.l_div_u
(...)
DEFC L_DIVENTRY = entry - l_div_u

-- -- -- --

XLIB l_div

LIB l_div_u
XREF L_DIVENTRY

IF !ARCHAIC
.l_div
(...)
call l_div_u + L_DIVENTRY ; unsigned divide but skip zero check


....this latest line is #66
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Is this with the latest changes to z80asm? It looks like a z80asm bug with defc. "DEFC L_DIVENTRY = entry - l_div_u" should result in a small positive constant and " l_div_u + L_DIVENTRY" should not evaluate to a large positive number or a small negative one.

The mod operator that is in there now is incorrect -- the remainder in signed division should take the sign of the dividend and it's being given the sign of the divisor instead. I can copy the division code in the new lib over to fix that but I'll wait until Paulo can have a look.
pscust
Well known member
Posts: 194
Joined: Thu Jun 23, 2011 3:34 pm

Post by pscust »

I have found the problem in z80asm, but the solution requires a complete rewrite of the expression evaluator.

A work around is available since the original (before I started maintaining it) assembler: the '#' operator.

The code works correctly if the '#' (transform address into constant) is used:

Code: Select all

DEFC L_DIVENTRY = # entry - l_div_u
Explanation:
The expression (entry - l_div_u) is tagged by the expression evaluator as relocatable and stored in the object file with the correct value (4) but with the 'A'ddress tag. At link time, the value (4) is added to the base address of the module to compute a nonsense value.

To solve this, the expression evaluator needs to recognize that a subtraction of two labels of the same section in the same module is a constant and not a relocatable address, and has to be stored in the object file tagged as 'C'onstant. To be able to do this, the expression evaluator needs to build the whole parse tree of the expression, and check the address tag on each of the subtraction operands.

Today the expression evaluator only keeps a global address flag for the whole expression, and keeps the operators and operands in a stack, with no chance to check the type of each element.
stefano
Well known member
Posts: 2151
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Fascinating and.. complex.
Please go ahead :)
stefano
Well known member
Posts: 2151
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Thinking back to this topic, I'm wondering if it is really z80asm needing a fix.
As far as I can recall this pre-computed offset was introduced by Alvin for the 'callee' stuff.
It was a clever way to overcome to the z80asm limits which was permitting to declare (and refer to) only one single 'public' address per module.
Perhaps if we find a cleaner way to get to the same result..
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

stefano wrote:Thinking back to this topic, I'm wondering if it is really z80asm needing a fix.
As far as I can recall this pre-computed offset was introduced by Alvin for the 'callee' stuff.
It's the recent changes to z80asm. defc has been modified to be able to hold a relocatable value resolved at link time, like regular labels. The old defc only allowed you to define constants that needed to be resolved right away within the source file.

The changes allow aliases to be defined:

====

PUBLIC array_size

array_size:

....
ret

====

PUBLIC vector_size

EXTERN array_size

defc vector_size = array_size

====


Now "vector_size" can be defined as an alias to array_size without using any memory. We used to have to place a jump to array_size inside vector_size, which took 3 bytes and 10 cycles.

That's the change that inadvertently broke the offset calculation.
It was a clever way to overcome to the z80asm limits which was permitting to declare (and refer to) only one single 'public' address per module.
Perhaps if we find a cleaner way to get to the same result..
That was the old way.. the new way is we're allowed to have multiple exported global symbols from the same source file (just declare all the entry points you want as PUBLIC). When we could only have one PUBLIC symbol, the offset trick allowed other entry points to be defined as the symbol + constant offset in source code. It only affects legacy code but there are quite a few places where the offset trick is used and Paulo has already fixed them by prefixing the defcs with '#' to force the subtractions to be classified as constants.

So we're good, better if we abandon the old and adopt the new cleaner methods.
stefano
Well known member
Posts: 2151
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Agreed. Paulo, I think you can leave things as they are for a bit while we destroy the legacy libraries by fixing them :D
pscust
Well known member
Posts: 194
Joined: Thu Jun 23, 2011 3:34 pm

Post by pscust »

Good. I'll try to keep up not-destoying stuff...:)
Post Reply