/***************************************************************************** Licensed to Accellera Systems Initiative Inc. (Accellera) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. Accellera licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ /***************************************************************************** stack_alignment.cpp -- This example shows the crash of an fxsave instruction in the sc_thread stack environment, but not in the original linux process stack, which is correctly aligned on first function. Please note that this test probably runs OK on a faulty implementation in 64-bit in general (depending on your libc implementation), but will crash for sure in 32-bit. Original Author: Eric Paire, STMicroelectronics *****************************************************************************/ /***************************************************************************** MODIFICATION LOG - modifiers, enter your name, affiliation, date and changes you are making here. Name, Affiliation, Date: Description of Modification: *****************************************************************************/ #include "systemc.h" /* * This program exhibits a bug in the management by QT of the stack of each * SystemC process. At least on i686 & x86_64, GCC makes the assumption that * the stack is aligned on a 16-byte boundary on each C/C++ function entry. * This convention allows GCC to respects constraints of automatic (stack) * variable alignment, using the __attribute)__ ((align(X))) GCC extension. * * The X is known to be 16 for i686 & x86_64, as this is the largest alignment * required by instructions operands, actually used by fxsave instruction. * * The attached code shows up the problem by crashing when fxsave is executed * in a SystemC thread, and executing correctly the *same* code on the initial * process stack, as initialized by the libc runtime. * * This misbehavior does not occur systematically for x86_64 (no crash, * or crash difficult to reproduce with standard malloc()), but often does * with i686. Notice that the instruction with the right alignment is shown * when using the myfpxregs address which is aligned on 16-byte boundary. */ #if defined(__x86_64__) # define FXSAVE "fxsaveq" #else # define FXSAVE "fxsave" #endif #if defined(__GNUC__) # define ALIGNED_ARRAY( Type, Name, Size, Align ) \ Type Name[Size] __attribute__((aligned(Align))) #elif defined(_MSC_VER) # define ALIGNED_ARRAY( Type, Name, Size, Align ) \ __declspec(align(Align)) Type Name[Size] #endif #if defined(__GNUC__) && ( defined(__x86_64__) || defined(__i386__) ) # define ASM( Assembly ) __asm__ __volatile__( Assembly ) #else # define ASM( Assembly ) /* not implemented */ #endif // Class SC_MODULE(C) { public: SC_CTOR(C) { SC_THREAD(run); } void run(void) { ALIGNED_ARRAY( char, fpxregs64, 512+15, 16 ); cout << "Inside C::run() " << endl; // manually enforce alignment (volatile to avoid optmizations) char * volatile myfpxregs = fpxregs64; while ((uintptr_t)myfpxregs & 0xF) myfpxregs++; // the "real" requirement: enforced alignment works sc_assert( !((uintptr_t)fpxregs64 & 0xF) ); sc_assert( !((uintptr_t)myfpxregs & 0xF) ); sc_assert( myfpxregs == fpxregs64 ); // test assembly on supported platforms ASM( FXSAVE " (%0)" :: "r"(myfpxregs) ); cout << "Between C::run() " << endl; ASM( FXSAVE " %0" : "=m"(fpxregs64) ); cout << "Out of C::run() " << endl; } }; int sc_main(int , char** ) { C the_C("C"); ALIGNED_ARRAY( char, fpxregs64, 512, 16 ); cout << "Inside sc_main() " << endl; ASM( FXSAVE " %0" : "=m"(fpxregs64) ); sc_start(1, SC_NS); cout << "Out of sc_main() " << endl; return 0; }