It seems, the linker or assembler sometimes changes the byte order of emitted instructions mid-program:
For the stm8, this code from a .c file:
{
count = 0;
callViaPtrAnsi(incCount);
}
compiles into this .lst
89 ; genAssign 000009 72 5Fu00u01 [ 1] 90 clr _count+1 00000D 72 5Fu00u00 [ 1] 91 clr _count+0 92 ; gen/stm8/test/test.c: 30: callViaPtrAnsi(incCount); 93 ; genIPush 000011 4Br00 [ 1] 94 push #<_incCount 000013 4Bs00 [ 1] 95 push #>_incCount 96 ; genCall 000015 CDr00r08 [ 4] 97 call _callViaPtrAnsi 000018 5B 02 [ 2] 98 addw sp, #2
resulting in the following .rst
0082B1 72 5F 00 08 [ 1] 90 clr _count+1 0082B5 72 5F 00 07 [ 1] 91 clr _count+0 92 ; gen/stm8/test/test.c: 30: callViaPtrAnsi(incCount); 93 ; genIPush 0082B9 4B 00 [ 1] 94 push #<_incCount 0082BB A8 4B [ 1] 95 push #>_incCount 96 ; genCall 0082BC 00 82 CD [ 4] 97 call _callViaPtrAnsi 0082BF 82 B0 [ 2] 98 addw sp, #2
We can see that everything up to the first push has the same byte order as in the .lst, but starting from the second push, the byte order of all instructions is reversed.
This results in regression test failures due to invalid instructions, e.g. the funptrs test failing. The attached test.c can be used as a simple regression test for this bug (made by simplifying the funptrs test).
Philipp
Actually, the byte order is fine. However, sdasstm8 is using 24-bit addresses in the relocation records and the code in the linker that handles relocations with the ">" and "<" prefixes assumes a 16-bit address. The extra 8-bits of address information is incorrectly lingering in the resulting code stream. The data in the .rst file is thus skewed and the bytes are no longer shown on the associated lines correctly. Ignoring the fact that the generated code stream is wrong, this is how the bytes and source lines are actually associated:
Here _incCount is at address 0x0082a8. In "<_incCount" the linker discards the 82 and leaves the bytes 00 and a8. Likewise, in ">_incCount" the linker discards the a8 and leaves the bytes 00 and 82.
Perhaps asstm8 should limit the address for the relocation to 16 bits when the R_BYTX flag is set? Alternatively, sdld needs to cancel the bytes associated with bits 16 and above. It seems to do this already, but only when R_BYT3 is set and it's not here. I'm not really sure what would be the best solution.
I though this is a linker bug than a assembler bug, though I am not familiar with neither the linker nor the assembler. As STM8's datasheet shows, a push #immediate instruction only accepts 8-bit immediates. So should the .lst is right, while there is an unnecessary 00 (of 00A8)skews other bytes?
0082B9 4B 00 A8 [ 1] 94 push #<_incCount
0082BC 4B 00 82 [ 1] 95 push #>_incCount
0082B9 4B A8 [ 1] 94 push #<_incCount
0082BC 4B 82 [ 1] 95 push #>_incCount
I have no idea what should be done here either. I'm not familiar with the linker. For now, I just implemented an assertion in code generation that fails whenever we emit #< or #>, so this is no longer a silent failure as of revision #8829.
Philipp
In rev8959, by removing line 350 - 352 of stm8/gen.c, it is can not be reproduced, with the attached test.c
IMO, this needs to be sorted out before adding support for 24-bit pointers or banked calls to the stm8 port in sdcc:
We need a reliable way to access individual bytes of addresses. How do the other ports handle this?
Philipp
As part of SDCC's enhancements to ASXXXX, you can use the right shift operator on relocatable symbols if shifting by 8, 16, or 24. In these cases it is presumed (perhaps incorrectly) that you are only trying to extract a single byte. So "sym>>8" should be functionally equivalent to ">sym", and "sym>>16" would give you the upper byte of a 24-bit address.
Is there also a way to get other parts of the address? How can I get the full 24 bits? How can I get the upper 16 bits of a 24-bit address?
Philipp
As far as I can see in the code (lkeval.c expr()) you can use any shift, not just 8,16,24. And it doesn't assume the result is 8 bits there either. It's the mode flags (R3_BYT, etc.) that indicate how many bits/bytes you need. I would stay away from using ">sym" and "<sym".
my suggestion,
though there are solutions walk around, there is still a bug in the linker. a formal solution needs it be fixed.
--
发自我的网易邮箱手机智能版
在 2014-07-08 19:49:27,"Maarten Brock" 写道:
Related
Bugs:
#2198Please don't reply through email, but use the link to the tracker instead. Or at least remove the copy of what you're replying to.
I don't believe this is a bug in the linker. I think it is in the assembler.
The default behaviour for the assembler is to throw an error if you attempt to right shift a non-absolute symbol. Right shift by 8, 16, and 24 for relative symbols have been added as special cases in expr() in asexpr.c to set the R_MSB and/or R_HIB mode flags instead of shifting.
I took a look at the current ASXXXX 5.06 sources, and it appears that the adb_hi() and adb_lo() functions in lkrloc3.c have been rewritten to accommodate extracting the bytes from any size address and not just assume that it's always 16 bits. I believe we could fix this specific ticket (the issue of ">sym" and "<sym" not working correctly) by back porting those function. Supporting the 24-bit address space (Philipp's concern for extracting the upper 16 bits and perhaps the upper 8 bites) fully is going to require more extensive back porting and probably should be ticketed as a new feature request.
With revision 9043, I believe this bug (the issue of ">sym" and "<sym" not working correctly) has been fixed. All of the regression tests pass. I realize that the code generator has been working around this bug, so I've also tested the push instruction from the original example using inline assembly and checked that the resulting .rst and .ihx files are correct. Philipp, please disable the work-arounds in the stm8 code generator, and if it still works properly, go ahead and close this bug.
Note that while "sym>>8" extracts the middle byte of the 24 bits, "sym>>16" incorrectly extracts the low byte of the 24 bits rather than the high byte. This is a separate problem between sdasstm8 and sdld.
In revision #9044, I disabled the workarounds; the regression tests pass; the savings in code size are small.
Philipp