C++程序  |  80行  |  1.68 KB


/*
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;
}