blob: e20395e2f91826f64063adec984aecd86dded8ad [file] [log] [blame]
/*****************************************************************************
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;
}