sim: ppc: switch register read/writes to union to avoid aliasing issues

This code creates a small buffer on the stack w/alloca, then proceeds to
write to it with a cast to a pointer type based on the register type, then
reads from it with a cast to a pointer type based on the register size.
gcc will flags only one of these lines as "maybe used uninitialized", but
it seems to track back to this memory abuse.

Create a large union with all the possible types that this code will read
or write as, and then use those.  It's a bit ugly, but is probably better
than using raw memcpy's everywhere.
This commit is contained in:
Mike Frysinger
2024-01-10 23:35:49 -05:00
parent 9be58d0790
commit dcc6c863ed

View File

@@ -789,7 +789,21 @@ psim_read_register(psim *system,
transfer_mode mode)
{
register_descriptions description;
char *cooked_buf;
union {
uint8_t bytes[16];
unsigned_word unsigned_word;
unsigned_1 unsigned_1;
unsigned_2 unsigned_2;
unsigned_4 unsigned_4;
unsigned_8 unsigned_8;
creg creg;
fpreg fpreg;
fpscreg fpscreg;
gpreg gpreg;
msreg msreg;
spreg spreg;
sreg sreg;
} cooked_buf;
cpu *processor;
/* find our processor */
@@ -808,81 +822,80 @@ psim_read_register(psim *system,
description = register_description(reg);
if (description.type == reg_invalid)
return 0;
cooked_buf = alloca (description.size);
/* get the cooked value */
switch (description.type) {
case reg_gpr:
*(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
cooked_buf.gpreg = cpu_registers(processor)->gpr[description.index];
break;
case reg_spr:
*(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
cooked_buf.spreg = cpu_registers(processor)->spr[description.index];
break;
case reg_sr:
*(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
cooked_buf.sreg = cpu_registers(processor)->sr[description.index];
break;
case reg_fpr:
*(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
cooked_buf.fpreg = cpu_registers(processor)->fpr[description.index];
break;
case reg_pc:
*(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
cooked_buf.unsigned_word = cpu_get_program_counter(processor);
break;
case reg_cr:
*(creg*)cooked_buf = cpu_registers(processor)->cr;
cooked_buf.creg = cpu_registers(processor)->cr;
break;
case reg_msr:
*(msreg*)cooked_buf = cpu_registers(processor)->msr;
cooked_buf.msreg = cpu_registers(processor)->msr;
break;
case reg_fpscr:
*(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr;
cooked_buf.fpscreg = cpu_registers(processor)->fpscr;
break;
case reg_insns:
*(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
cooked_buf.unsigned_word = mon_get_number_of_insns(system->monitor,
which_cpu);
break;
case reg_stalls:
if (cpu_model(processor) == NULL)
error("$stalls only valid if processor unit model enabled (-I)\n");
*(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
cooked_buf.unsigned_word = model_get_number_of_stalls(cpu_model(processor));
break;
case reg_cycles:
if (cpu_model(processor) == NULL)
error("$cycles only valid if processor unit model enabled (-I)\n");
*(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
cooked_buf.unsigned_word = model_get_number_of_cycles(cpu_model(processor));
break;
#ifdef WITH_ALTIVEC
case reg_vr:
*(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index];
cooked_buf.vreg = cpu_registers(processor)->altivec.vr[description.index];
break;
case reg_vscr:
*(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr;
cooked_buf.vscreg = cpu_registers(processor)->altivec.vscr;
break;
#endif
#ifdef WITH_E500
case reg_gprh:
*(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index];
cooked_buf.gpreg = cpu_registers(processor)->e500.gprh[description.index];
break;
case reg_evr:
*(uint64_t*)cooked_buf = EVR(description.index);
cooked_buf.uint64_t = EVR(description.index);
break;
case reg_acc:
*(accreg*)cooked_buf = cpu_registers(processor)->e500.acc;
cooked_buf.accreg = cpu_registers(processor)->e500.acc;
break;
#endif
@@ -898,36 +911,36 @@ psim_read_register(psim *system,
/* FIXME - assumes that all registers are simple integers */
switch (description.size) {
case 1:
*(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
*(unsigned_1*)buf = H2T_1(cooked_buf.unsigned_1);
break;
case 2:
*(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
*(unsigned_2*)buf = H2T_2(cooked_buf.unsigned_2);
break;
case 4:
*(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
*(unsigned_4*)buf = H2T_4(cooked_buf.unsigned_4);
break;
case 8:
*(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
*(unsigned_8*)buf = H2T_8(cooked_buf.unsigned_8);
break;
#ifdef WITH_ALTIVEC
case 16:
if (HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
{
union { vreg v; unsigned_8 d[2]; } h, t;
memcpy(&h.v/*dest*/, cooked_buf/*src*/, description.size);
memcpy(&h.v/*dest*/, cooked_buf.bytes/*src*/, description.size);
{ _SWAP_8(t.d[0] =, h.d[1]); }
{ _SWAP_8(t.d[1] =, h.d[0]); }
memcpy(buf/*dest*/, &t/*src*/, description.size);
break;
}
else
memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
memcpy(buf/*dest*/, cooked_buf.bytes/*src*/, description.size);
break;
#endif
}
}
else {
memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
memcpy(buf/*dest*/, cooked_buf.bytes/*src*/, description.size);
}
return description.size;
@@ -945,7 +958,21 @@ psim_write_register(psim *system,
{
cpu *processor;
register_descriptions description;
char *cooked_buf;
union {
uint8_t bytes[16];
unsigned_word unsigned_word;
unsigned_1 unsigned_1;
unsigned_2 unsigned_2;
unsigned_4 unsigned_4;
unsigned_8 unsigned_8;
creg creg;
fpreg fpreg;
fpscreg fpscreg;
gpreg gpreg;
msreg msreg;
spreg spreg;
sreg sreg;
} cooked_buf;
/* find our processor */
if (which_cpu == MAX_NR_PROCESSORS) {
@@ -960,7 +987,6 @@ psim_write_register(psim *system,
description = register_description(reg);
if (description.type == reg_invalid)
return 0;
cooked_buf = alloca (description.size);
if (which_cpu == -1) {
int i;
@@ -977,16 +1003,16 @@ psim_write_register(psim *system,
if (mode == raw_transfer) {
switch (description.size) {
case 1:
*(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
cooked_buf.unsigned_1 = T2H_1(*(unsigned_1*)buf);
break;
case 2:
*(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
cooked_buf.unsigned_2 = T2H_2(*(unsigned_2*)buf);
break;
case 4:
*(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
cooked_buf.unsigned_4 = T2H_4(*(unsigned_4*)buf);
break;
case 8:
*(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
cooked_buf.unsigned_8 = T2H_8(*(unsigned_8*)buf);
break;
#ifdef WITH_ALTIVEC
case 16:
@@ -996,86 +1022,85 @@ psim_write_register(psim *system,
memcpy(&t.v/*dest*/, buf/*src*/, description.size);
{ _SWAP_8(h.d[0] =, t.d[1]); }
{ _SWAP_8(h.d[1] =, t.d[0]); }
memcpy(cooked_buf/*dest*/, &h/*src*/, description.size);
memcpy(cooked_buf.bytes/*dest*/, &h/*src*/, description.size);
break;
}
else
memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
memcpy(cooked_buf.bytes/*dest*/, buf/*src*/, description.size);
#endif
}
}
else {
memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
memcpy(cooked_buf.bytes/*dest*/, buf/*src*/, description.size);
}
/* put the cooked value into the register */
switch (description.type) {
case reg_gpr:
cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
cpu_registers(processor)->gpr[description.index] = cooked_buf.gpreg;
break;
case reg_fpr:
cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
cpu_registers(processor)->fpr[description.index] = cooked_buf.fpreg;
break;
case reg_pc:
cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
cpu_set_program_counter(processor, cooked_buf.unsigned_word);
break;
case reg_spr:
cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
cpu_registers(processor)->spr[description.index] = cooked_buf.spreg;
break;
case reg_sr:
cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
cpu_registers(processor)->sr[description.index] = cooked_buf.sreg;
break;
case reg_cr:
cpu_registers(processor)->cr = *(creg*)cooked_buf;
cpu_registers(processor)->cr = cooked_buf.creg;
break;
case reg_msr:
cpu_registers(processor)->msr = *(msreg*)cooked_buf;
cpu_registers(processor)->msr = cooked_buf.msreg;
break;
case reg_fpscr:
cpu_registers(processor)->fpscr = *(fpscreg*)cooked_buf;
cpu_registers(processor)->fpscr = cooked_buf.fpscreg;
break;
#ifdef WITH_E500
case reg_gprh:
cpu_registers(processor)->e500.gprh[description.index] = *(gpreg*)cooked_buf;
cpu_registers(processor)->e500.gprh[description.index] = cooked_buf.gpreg;
break;
case reg_evr:
{
uint64_t v;
v = *(uint64_t*)cooked_buf;
v = cooked_buf.uint64_t;
cpu_registers(processor)->e500.gprh[description.index] = v >> 32;
cpu_registers(processor)->gpr[description.index] = v;
break;
}
case reg_acc:
cpu_registers(processor)->e500.acc = *(accreg*)cooked_buf;
cpu_registers(processor)->e500.acc = cooked_buf.accreg;
break;
#endif
#ifdef WITH_ALTIVEC
case reg_vr:
cpu_registers(processor)->altivec.vr[description.index] = *(vreg*)cooked_buf;
cpu_registers(processor)->altivec.vr[description.index] = cooked_buf.vreg;
break;
case reg_vscr:
cpu_registers(processor)->altivec.vscr = *(vscreg*)cooked_buf;
cpu_registers(processor)->altivec.vscr = cooked_buf.vscreg;
break;
#endif
default:
printf_filtered("psim_write_register(processor=%p,cooked_buf=%p,reg=%s) %s\n",
processor, cooked_buf, reg,
"read of this register unimplemented");
printf_filtered("psim_write_register(processor=%p,buf=%p,reg=%s) %s\n",
processor, buf, reg, "read of this register unimplemented");
return 0;
}