digidotcom / DCRabbit_9

This repository is the Open Source release of the libraries and sample code from Dynamic C 9, an integrated development environment for Digi International's embedded systems based on the Rabbit 2000 and 3000 microprocessors.
http://www.digi.com
Mozilla Public License 2.0
10 stars 11 forks source link

Compiler bug in DC 9.30 and later generates incorrect opcode sequence #9

Open tomlogic opened 1 year ago

tomlogic commented 1 year ago

Digi has discovered a bug present in Dynamic C 9.30 (but not 9.25) related to code generation for assigning 8-bit values to 16-bit variables via a pointer. The bug has been in all releases of Dynamic C from 9.30 through 9.62A.

Some examples of affected C statements:

pt->int_val = char_val;          // impacts pointers to structures
*stack_int_ptr = char_val;       // impacts pointers on stack
int_array[7] = char_val;         // impacts arrays w/constant index
int_array[int_val] = char_val;   // impacts arrays w/variable index
int_ptr[7] = char_val;           // impacts array syntax with pointer
*(int_ptr + 7) = char_val;       // impacts dereferenced pointer
int_ptr[int_val] = char_val;     // impacts pointer w/variable index

The work around is quite simple. Users can either wrap char_val in parentheses, or explicitly cast it to int:

*int_ptr = char_val;            // affected
*int_ptr = (char_val);          // workaround
*int_ptr = (int)char_val;       // workaround

Dynamic C 9.25 generates the following 11-byte opcode sequence – upon entry, HL holds the address of the integer destination:

1de9 E5       push   hl                10
1dea 2A1BB8   ld     hl,(0xB81B)       11
1ded 2600     ld     h,0x00             4
1def FDE1     pop    iy                 9
1df1 FDF400   ld     (iy+0),hl         13

Note the protection of HL before loading the byte at 0xB81B, and the use of IY to write the 16-bit value to memory.

Starting with Dynamic C 9.30, the compiler generates this 9-byte sequence:

1a88 3A18BA   ld a, (0xBA18)                 9
1a8b 6F       ld l, a                        2
1a8c 2600     ld h, 0x00                     4
1a8e DDF400   ld (hl + 0), hl                13

Effectively overwriting the destination address with the value to write.

To assess impact, customers can search their binary files for the sequence 6F 26 00 DD F4 00, which should be unique and unlikely to appear outside of this specific opcode sequence. They can also search the assembly listing (.LST file) for the DDF400 sequence corresponding to ld (hl + 0), hl which is unlikely to occur outside of this bug.

Users can patch the sequence after the ld a, (0xBA18) with the following opcodes, making it possible to "fix" existing .bin files containing the 6F 26 00 DD F4 00 sequence in cases where it isn't possible to update and re-compile source code.

77       ld (hl), a
23       inc hl
AF       xor a
77       ld (hl), a
2B       dec hl         ; restore original HL value
00       nop            ; keep original byte count

We don’t necessarily have to restore the HL value after the write, but we have two bytes to spare and might as well do it instead of just adding another NOP.

We are adding this as a KNOWN ISSUE and have no plans to update the compiler to fix this bug. This is the first report of the problem since releasing Dynamic C 9.30 over 16 years ago.

tomlogic commented 1 year ago

Be sure to "subscribe" to notifications for this issue to be kept up to date on any updates regarding this issue.