stack_alignment.cpp revision 12855:588919e0e4aa
1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  stack_alignment.cpp -- This example shows the crash of an fxsave instruction
23                         in the sc_thread stack environment, but not in the
24                         original linux process stack, which is correctly
25                         aligned on first function.
26
27  Please note that this test probably runs OK on a faulty implementation in
28  64-bit in general (depending on your libc implementation), but will crash
29  for sure in 32-bit.
30
31  Original Author: Eric Paire, STMicroelectronics
32
33 *****************************************************************************/
34
35/*****************************************************************************
36
37  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
38  changes you are making here.
39
40      Name, Affiliation, Date:
41  Description of Modification:
42
43 *****************************************************************************/
44
45#include "systemc.h"
46
47/*
48 * This program exhibits a bug in the management by QT of the stack of each
49 * SystemC process. At least on i686 & x86_64, GCC makes the assumption that
50 * the stack is aligned on a 16-byte boundary on each C/C++ function entry.
51 * This convention allows GCC to respects constraints of automatic (stack)
52 * variable alignment, using the __attribute)__ ((align(X))) GCC extension.
53 *
54 * The X is known to be 16 for i686 & x86_64, as this is the largest alignment
55 * required by instructions operands, actually used by fxsave instruction.
56 *
57 * The attached code shows up the problem by crashing when fxsave is executed
58 * in a SystemC thread, and executing correctly the *same* code on the initial
59 * process stack, as initialized by the libc runtime.
60 *
61 * This misbehavior does not occur systematically for x86_64 (no crash,
62 * or crash difficult to reproduce with standard malloc()), but often does
63 * with i686. Notice that the instruction with the right alignment is shown
64 * when using the myfpxregs address which is aligned on 16-byte boundary.
65 */
66
67#if defined(__x86_64__)
68#  define FXSAVE "fxsaveq"
69#else
70#  define FXSAVE "fxsave"
71#endif
72
73#if defined(__GNUC__)
74#  define ALIGNED_ARRAY( Type, Name, Size, Align ) \
75	  Type Name[Size] __attribute__((aligned(Align)))
76#elif defined(_MSC_VER)
77#  define ALIGNED_ARRAY( Type, Name, Size, Align ) \
78      __declspec(align(Align)) Type Name[Size]
79#endif
80
81#if defined(__GNUC__) && ( defined(__x86_64__) || defined(__i386__) )
82#  define ASM( Assembly ) __asm__ __volatile__( Assembly )
83#else
84#  define ASM( Assembly ) /* not implemented */
85#endif
86
87// Class
88SC_MODULE(C)
89{
90public:
91    SC_CTOR(C) {
92        SC_THREAD(run);
93    }
94    void run(void)
95    {
96        ALIGNED_ARRAY( char, fpxregs64, 512+15, 16 );
97
98        cout << "Inside C::run() " << endl;
99
100        // manually enforce alignment (volatile to avoid optmizations)
101        char * volatile myfpxregs = fpxregs64;
102        while ((uintptr_t)myfpxregs & 0xF)
103            myfpxregs++;
104
105        // the "real" requirement: enforced alignment works
106        sc_assert( !((uintptr_t)fpxregs64 & 0xF) );
107        sc_assert( !((uintptr_t)myfpxregs & 0xF) );
108        sc_assert( myfpxregs == fpxregs64 );
109
110        // test assembly on supported platforms
111        ASM( FXSAVE " (%0)" :: "r"(myfpxregs) );
112        cout << "Between C::run() " << endl;
113        ASM( FXSAVE " %0" : "=m"(fpxregs64) );
114
115        cout << "Out of C::run() " << endl;
116    }
117};
118
119int sc_main(int , char** ) {
120  C the_C("C");
121
122  ALIGNED_ARRAY( char, fpxregs64, 512, 16 );
123
124  cout << "Inside sc_main() " << endl;
125  ASM( FXSAVE " %0" : "=m"(fpxregs64) );
126  sc_start(1, SC_NS);
127  cout << "Out of sc_main() " << endl;
128  return 0;
129}
130