https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67529

            Bug ID: 67529
           Summary: rx-elf C++ inherited class malformed call to
                    overridden methods
           Product: gcc
           Version: 5.2.0
            Status: UNCONFIRMED
          Severity: critical
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ericns1 at spirilis dot net
  Target Milestone: ---

Created attachment 36313
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=36313&action=edit
Files needed to reproduce this bug using rx-elf-g++ cmd listed in bug report.

I've been able to reproduce what appears to be a glitch in the rx-elf-g++ C++
compiler.  Originally found on GCC 4.8.4 (KPIT Cummins' GNURXv15.01-SP1 release
that pairs with Renesas' e2studio IDE), I have compiled GCC 5.2.0 from scratch
for the rx-elf target and confirmed similar ASM output.

In this example, I am writing an all-pure virtual method-laden class to define
an interface of sorts for a common hardware API, and writing implementation
classes which override the pure virtual methods with their correct
implementations.  When a method inside the class attempts to execute another
method inside the class that was overriding a pure virtual method in the parent
class, the actual function call produced includes a JSR instruction against a
register value which appears to be derived from the in-SRAM address of the
object's data storage, not the actual in-Flash location of the function itself.

Example:

my_template_parent.h:
#ifndef MY_TEMPLATE_PARENT_H_
#define MY_TEMPLATE_PARENT_H_

#include <stdint.h>
#include <ctype.h>
#include <sys/cdefs.h>

class MyTemplateParent {
public:
        // prove it doesn't need to be a pure virtual function for the bug to
occur
        virtual void begin(void) { return; };
        virtual void check(void) = 0;
};



my_template.h:
#ifndef MY_TEMPLATE_H_
#define MY_TEMPLATE_H_

#include <stdint.h>
#include <ctype.h>
#include <sys/cdefs.h>
#include "my_template_parent.h"


class MyTemplate : MyTemplateParent {
private:
        uint8_t buffer[256];
        unsigned int head;
        uint8_t value = 0;

public:
        __noinline
        void begin(void) {
                head = 0;
                buffer[0] = value;
        }

        __noinline
        void begin(uint8_t val1) {
                buffer[1] = val1;
                //begin();  // set buffer[0] to value (template argument)
                check();
        };

        __noinline
        void check(void) {
                if (buffer[2] == 0xF3)
                        buffer[3] = 0xF3;
        }
};

#endif /* MY_TEMPLATE_H_ */


Main provided by "main.cpp":
#include "my_template.h"

MyTemplate obj;

int main(void)
{
        volatile unsigned long i = 0;

        obj.begin(33);
        while(1)
                i++;
}


Compiled using: rx-elf-g++ -T rx2108.ld -ffunction-sections -fdata-sections
-Wl,--gc-sections -D__RX_LITTLE_ENDIAN__=1 -DCPPAPP -mlittle-endian-data
-mcpu=rx200 -nofpu -o a.out main.cpp
(rx2108.ld provided as an attachment)

The assembler output, rx-elf-objdump -C -dS, produces the following for the
MyTemplate-related functions:



fff80160 <MyTemplateParent::begin()>:
fff80160:       7e a6                           push.l  r6
fff80162:       71 06 fc                        add     #-4, r0, r6
fff80165:       ef 60                           mov.l   r6, r0
fff80167:       e3 61                           mov.l   r1, [r6]
fff80169:       03                              nop
fff8016a:       3f 66 02                        rtsd    #8, r6-r6

fff8016d <MyTemplate::begin()>:
fff8016d:       6e 6b                           pushm   r6-r11
fff8016f:       71 06 fc                        add     #-4, r0, r6
fff80172:       ef 60                           mov.l   r6, r0
fff80174:       e3 61                           mov.l   r1, [r6]
fff80176:       ec 6a                           mov.l   [r6], r10
fff80178:       f9 a6 41 00                     mov.l   #0, 260[r10]
fff8017c:       ec 6a                           mov.l   [r6], r10
fff8017e:       ce ab 08 01                     mov.b   264[r10], r11
fff80182:       ec 6a                           mov.l   [r6], r10
fff80184:       c7 ab 04                        mov.b   r11, 4[r10]
fff80187:       03                              nop
fff80188:       3f 6b 07                        rtsd    #28, r6-r11

fff8018b <MyTemplate::begin(unsigned char)>:
fff8018b:       6e 6b                           pushm   r6-r11
fff8018d:       71 06 f8                        add     #-8, r0, r6
fff80190:       ef 60                           mov.l   r6, r0
fff80192:       e3 61                           mov.l   r1, [r6]
fff80194:       81 62                           mov.b   r2, 4[r6]
fff80196:       ec 6a                           mov.l   [r6], r10
fff80198:       cd 6b 04                        mov.b   4[r6], r11
fff8019b:       c7 ab 05                        mov.b   r11, 5[r10]
fff8019e:       ec 6a                           mov.l   [r6], r10
fff801a0:       ec aa                           mov.l   [r10], r10
fff801a2:       62 4a                           add     #4, r10
fff801a4:       ec aa                           mov.l   [r10], r10
fff801a6:       ec 61                           mov.l   [r6], r1
fff801a8:       7f 1a                           jsr     r10
fff801aa:       03                              nop
fff801ab:       3f 6b 08                        rtsd    #32, r6-r11

fff801ae <MyTemplate::check()>:
fff801ae:       7e aa                           push.l  r10
fff801b0:       7e a6                           push.l  r6
fff801b2:       71 06 fc                        add     #-4, r0, r6
fff801b5:       ef 60                           mov.l   r6, r0
fff801b7:       e3 61                           mov.l   r1, [r6]
fff801b9:       ec 6a                           mov.l   [r6], r10
fff801bb:       cd aa 06                        mov.b   6[r10], r10
fff801be:       5b aa                           movu.b  r10, r10
fff801c0:       75 5a f3                        cmp     #243, r10
fff801c3:       1f                              bne.s   fff801ca
<_idkey_0+0xfff801cb>
fff801c4:       ec 6a                           mov.l   [r6], r10
fff801c6:       f9 a4 07 f3                     mov.b   #243, 7[r10]
fff801ca:       03                              nop
fff801cb:       62 40                           add     #4, r0
fff801cd:       7e b6                           pop     r6
fff801cf:       7e ba                           pop     r10
fff801d1:       02                              rts


The critical piece is:
fff8019e:       ec 6a                           mov.l   [r6], r10
fff801a0:       ec aa                           mov.l   [r10], r10
fff801a2:       62 4a                           add     #4, r10
fff801a4:       ec aa                           mov.l   [r10], r10
fff801a6:       ec 61                           mov.l   [r6], r1
fff801a8:       7f 1a                           jsr     r10

JSR R10 .... appears from the Renesas IDE's debug view to branch the CPU to
address 0x00000000, at the beginning of SRAM.


On the other hand, if we break the inheritence by reworking my_template.h so it
no longer inherits from MyTemplateParent:
class MyTemplate {

...

the disassembled output looks a bit different:

fff80160 <MyTemplate::begin(unsigned char)>:
fff80160:       6e 6b                           pushm   r6-r11
fff80162:       71 06 f8                        add     #-8, r0, r6
fff80165:       ef 60                           mov.l   r6, r0
fff80167:       e3 61                           mov.l   r1, [r6]
fff80169:       81 62                           mov.b   r2, 4[r6]
fff8016b:       ec 6a                           mov.l   [r6], r10
fff8016d:       cd 6b 04                        mov.b   4[r6], r11
fff80170:       c7 ab 01                        mov.b   r11, 1[r10]
fff80173:       ec 61                           mov.l   [r6], r1
fff80175:       05 08 00 00                     bsr.a   fff8017d
<_idkey_0+0xfff8017e>
fff80179:       03                              nop
fff8017a:       3f 6b 08                        rtsd    #32, r6-r11

fff8017d <MyTemplate::check()>:
fff8017d:       7e aa                           push.l  r10
fff8017f:       7e a6                           push.l  r6
fff80181:       71 06 fc                        add     #-4, r0, r6
fff80184:       ef 60                           mov.l   r6, r0
fff80186:       e3 61                           mov.l   r1, [r6]
fff80188:       ec 6a                           mov.l   [r6], r10
fff8018a:       cd aa 02                        mov.b   2[r10], r10
fff8018d:       5b aa                           movu.b  r10, r10
fff8018f:       75 5a f3                        cmp     #243, r10
fff80192:       1f                              bne.s   fff80199
<_idkey_0+0xfff8019a>
fff80193:       ec 6a                           mov.l   [r6], r10
fff80195:       f9 a4 03 f3                     mov.b   #243, 3[r10]
fff80199:       03                              nop
fff8019a:       62 40                           add     #4, r0
fff8019c:       7e b6                           pop     r6
fff8019e:       7e ba                           pop     r10
fff801a0:       02                              rts

Here a "BSR.A" instruction is used to branch to the new function, and it runs
successfully.  You can try having MyTemplate::begin(uint8_t) call begin()
instead of check() .... the same JSR type of instruction results and it goes
off into lala land.

Reply via email to