File: std_reg_imm.c

package info (click to toggle)
valgrind 1%3A3.12.0~svn20160714-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 120,428 kB
  • ctags: 70,855
  • sloc: ansic: 674,645; exp: 26,134; xml: 21,574; asm: 7,570; cpp: 7,567; makefile: 7,380; sh: 6,188; perl: 5,855; haskell: 195
file content (79 lines) | stat: -rw-r--r-- 1,720 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/*
This is a regression test for the following problem, noticed by
Greg Parker:

vex ppc64 generates bad code for instruction sequences like this:

    li    r0, 2
    stdx  r3, r1, r0

gcc emits code like this when manipulating packed structures 
with 8-byte fields on 2-byte boundaries.

First, vex's optimizer substitutes a constant 0x2 for r0:

    ------ IMark(0x100000F34, 4) ------
    PUT(1024) = 0x100000F34:I64
    t3 = GET:I64(24)
    t14 = GET:I64(8)
    t13 = Add64(t14,0x2:I64)
    STbe(t13) = t3

Then instruction selection chooses `std` with an index not divisible by 4:

    -- STbe(Add64(GET:I64(8),0x2:I64)) = GET:I64(24)
    ldz %vR22,8(%r31)
    ldz %vR23,24(%r31)
    std %vR23,2(%vR22)

Finally, the assembler silently strips the index&3 part, 
because `std` can't encode that:

    std %r6,2(%r5)
    F8 C5 00 00 

...but 0xF8C50000 is `std r6, 0(r5)`, which writes to the wrong address.
*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef 
struct __attribute__ ((__packed__)) {
  char before[2];
  unsigned long long int w64;
  char after[6];
}
T;

void foo (T* t, unsigned long long int w)
{
  __asm__ __volatile__(
     "stdx %0,%1,%2"
     : : "b"(w), "b"(t), "b"(2) : "memory"
  );
}

int main ( void )
{
  T* t;
  unsigned char* p;
  int i;
  assert(sizeof(T) == 16);
  t = calloc(sizeof(T),1);
  assert(t);
  /* check t is 8-aligned.  This causes the write done by 'foo' to be
     misaligned by 2 as desired, triggering the bug. */
  assert(0 == (((unsigned long)t) & 7));
  foo(t, 0x1122334455667788);
  p = (unsigned char*)t;
  for (i = 0; i < 16; i++)
    if (p[i] == 0)
      printf(".."); 
    else
      printf("%02x", (int)p[i]);
  printf("\n");
  return 0;
}