-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Medium
-
Code Generation Tools
-
CODEGEN-10306
-
-
-
-
default
-
EABI cinit copy "compression" involves no actual compression. Instead the
cinit records include the actual data to be copied out during initialization
as well as the size of the data to be copied.
For small size initializations, the linker was incorrectly setting the number
of bytes to copy. This would result in a cinit record that could write over an adjacent initialized variable in memory during cinit.
Here's an example where var_copy_issue's cinit record will be generated with
incorrect size which then over writes the initialization of var_impacted:
main.c
#include <stdio.h> __attribute__((location(0xC001))) char var_copy_issue = 0xABCD; __attribute__((location(0xC002))) long var_impacted = 0XABCD1234; __attribute__((location(0xC004))) long long var_no_issue = 0xABCD1234BEEF5678; int main(void) { volatile long long s = var_copy_issue + var_impacted + var_no_issue; printf("var_copy_issue 0x%04x \n", var_copy_issue); printf("var_impacted 0x%lx \n", var_impacted); printf("var_no_issue 0x%llx \n", var_no_issue); return 0; }
Compile above with below that forces copy "compression":
cl2000 -v28 --float_support=fpu32 --abi=eabi main.c -z -llnk.cmd --cinit_compression=off
Running above generates this output:
var_copy_issue 0xabcd var_impacted 0xabcd0000 <-- should be 0xabcd1234 var_no_issue 0xabcd1234beef5678
Linker map file shows below entry for var_copy_issue with compression=copy and
run_size=1 which looks correct:
__TI_cinit_table @ 00081eba records: 5, size/record: 4, table size: 20 .TI.bound:var_no_issue: load addr=00081e9e, load size=00000008 bytes, run addr=0000c004, run size=00000004 bytes, compression=copy .TI.bound:var_impacted: load addr=00081ea6, load size=00000006 bytes, run addr=0000c002, run size=00000002 bytes, compression=copy .TI.bound:var_copy_issue: load addr=00081eac, load size=00000005 bytes, run addr=0000c001, run size=00000001 bytes, compression=copy
However, dissassembling above executable and viewing var_copy_issue's cinit
record shows the bug with incorrect run_size set to 2:
00081ea6 0000 .word 0x0000 cinit handler index 00081ea7 0000 .word 0x0000 padding to align below run_size 00081ea8 0002 .word 0x0002 32bit run_size=2 but should instead be 1 00081ea9 0000 .word 0x0000 00081eaa 1234 .word 0x1234 var_copy_issue's initialization value 00081eab abcd .word 0xabcd padding to align next cinit record
More details per ISA target:
Below table shows the cases with the issue.
NOTE: some targets have 8bit bytes and some have 16bit bytes. Both are
affected.
The second column indicates the size of variable(s) that could cause the issue.
The third column shows the copy-record size that was incorrectly being used to set the copy-size.
var bytes handler_index+padding
TIARMCLANG/ARM 1-3 8bit bytes 4 bytes
MSP 1 8bit byte 2 bytes
C29 1-3 8bit byte 4 bytes
C60 1-3 8bit byte 4 bytes
C70 1-7 8bit byte 8 bytes this is worst impacted
C28 1 16bit "byte" 2 16bit "bytes"
The bug could occur for cases where the number of bytes of variable(s) to
copy-initialize is less than above column 3's entry for a copy-record's
handler_index+padding.
Additionally, for the bug to occur, there needs to be a variable in memory
located directly after above variable with the cinit issue. And the sequence
of cinit initializations needs to initialize var_impacted first followed by
initialization of var_copy_issue (which then overwrites the earlier
initialization).
The other way this issue could occur is if a cinit record size to copy
was set smaller than the variable size. This would result in a variable
not having the full initialization performed.