#2198 Linker relocation failure extracting single byte from 24-bit address

closed-fixed
Erik Petrich
None
STM8
6
2014-07-11
2013-07-19
No

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

1 Attachments

Related

Bugs: #2198

Discussion

    • Priority: 5 --> 7
     
  • Erik Petrich
    Erik Petrich
    2013-09-02

    • summary: Byte order confusion --> Linker relocation failure extracting single byte from 24-bit address
     
  • Erik Petrich
    Erik Petrich
    2013-09-02

    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:

      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 A8         [ 1]   94     push    #<_incCount
      0082BC 4B 00 82         [ 1]   95     push    #>_incCount
                                     96 ; genCall
      0082BF CD 82 B0         [ 4]   97     call    _callViaPtrAnsi
      0082C2 5B 02            [ 2]   98     addw    sp, #2
    

    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.

     
    • Ben Shi
      Ben Shi
      2014-02-11

      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

     
    • Priority: 7 --> 6
     
  • Maarten Brock
    Maarten Brock
    2013-12-18

    • Category: other --> STM8
     
  • Ben Shi
    Ben Shi
    2014-03-10

    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

     
  • Erik Petrich
    Erik Petrich
    2014-07-05

    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

     
  • Maarten Brock
    Maarten Brock
    2014-07-08

    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".

     
    • Ben Shi
      Ben Shi
      2014-07-08

      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" 写道:

      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 "


      [bugs:#2198] Linker relocation failure extracting single byte from 24-bit address

      Status: open
      Created: Fri Jul 19, 2013 10:22 AM UTC by Philipp Klaus Krause
      Last Updated: Sat Jul 05, 2014 09:09 AM UTC
      Owner: nobody

      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    #      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    #      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


      Sent from sourceforge.net because you indicated interest in

      To unsubscribe from further messages, please visit

       

      Related

      Bugs: #2198

  • Maarten Brock
    Maarten Brock
    2014-07-08

    Please 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.

     
  • Erik Petrich
    Erik Petrich
    2014-07-08

    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.

     
  • Erik Petrich
    Erik Petrich
    2014-07-09

    • assigned_to: Erik Petrich
     
  • Erik Petrich
    Erik Petrich
    2014-07-09

    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.

     
    • status: open --> closed-fixed
     
  • In revision #9044, I disabled the workarounds; the regression tests pass; the savings in code size are small.

    Philipp