
#include <stdio.h> #define CPU_SPARC ( defined( __sparc ) || defined( sparc ) ) #include "safe_access.h" #pragma pack( 1 ) struct foo { unsigned char a; // doesn't need safe access SA( unsigned int ) b; // unaligned int needs safe access }; #pragma pack() int main( int, char ** ) { foo foo = { 0xAA, 0xBBBBBBBB }; unsigned char a = foo.a; unsigned int b = foo.b; printf( " &a = %p a = %x \n", &foo.a, a ); printf( " &b = %p b = %x \n", &foo.b, b ); foo.a = 0x12; foo.b = 0x34567890; printf( " a = %x \n", int( foo.a ) ); printf( " b = %x \n", int( foo.b ) ); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Safe Access // // These routines are used to access memory addresses that would cause bus-errors on the // SPARC platform if accessed in the normal C++ way, due to misaligned memory addresses. //--------------------------------------------------------------------------------------- #ifndef __SAFE_ACCESS_H__ #define __SAFE_ACCESS_H__ #pragma once //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Safe Variable Copy // // These routines behave like memcpy function calls, but are specialized for data type // sizes 2, 4, and 8 bytes. It is designed to execute in the fewest number of assembly // instructions without calling memcpy. Under the SUN platform using SPARC processors, // crashes occur with bus-alignment errors when data is located at random addresses. //--------------------------------------------------------------------------------------- template< int Sizeof_Variable > void safe_variable_copy( void *, const void * ); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Specialization for sizeof( short ) // // safe_variable_copy< 2 >( &left, &right ) //--------------------------------------------------------------------------------------- template<> inline void safe_variable_copy< 2 >( void * left, const void * right ) { static_cast< char * >( left )[ 0 ] = static_cast< const char * >( right )[ 0 ]; static_cast< char * >( left )[ 1 ] = static_cast< const char * >( right )[ 1 ]; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Specialization for sizeof( int ) // // safe_variable_copy< 4 >( &left, &right ) //--------------------------------------------------------------------------------------- template<> inline void safe_variable_copy< 4 >( void * left, const void * right ) { static_cast< char * >( left )[ 0 ] = static_cast< const char * >( right )[ 0 ]; static_cast< char * >( left )[ 1 ] = static_cast< const char * >( right )[ 1 ]; static_cast< char * >( left )[ 2 ] = static_cast< const char * >( right )[ 2 ]; static_cast< char * >( left )[ 3 ] = static_cast< const char * >( right )[ 3 ]; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Specialization for sizeof( long long ) // // safe_variable_copy< 8 >( &left, &right ) //--------------------------------------------------------------------------------------- template<> inline void safe_variable_copy< 8 >( void * left, const void * right ) { static_cast< char * >( left )[ 0 ] = static_cast< const char * >( right )[ 0 ]; static_cast< char * >( left )[ 1 ] = static_cast< const char * >( right )[ 1 ]; static_cast< char * >( left )[ 2 ] = static_cast< const char * >( right )[ 2 ]; static_cast< char * >( left )[ 3 ] = static_cast< const char * >( right )[ 3 ]; static_cast< char * >( left )[ 4 ] = static_cast< const char * >( right )[ 4 ]; static_cast< char * >( left )[ 5 ] = static_cast< const char * >( right )[ 5 ]; static_cast< char * >( left )[ 6 ] = static_cast< const char * >( right )[ 6 ]; static_cast< char * >( left )[ 7 ] = static_cast< const char * >( right )[ 7 ]; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Safe Access // // This templated function is used to prevent a bus errors under the SUN SPARC systems. // We wrap the misaligned variables with a function call to this routine. //--------------------------------------------------------------------------------------- template< typename Ty > inline Ty safe_access( const Ty & value ) { Ty result; // access memory using a memory-aligned variable safe_variable_copy< sizeof( Ty ) >( &result, &value ); return result; // pass back the value from misaligned variable } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // Safe Access Data Wrapper // // This wrapper class is used to wrap data defined in structures that are possibly // misaligned for the computer's bus architecture. It is typically meant to be used // inside data structures that are packed using the #pragma pack(n). // // Example of usage: // #if 0 #pragma pack(1) struct Packed_Structure { u8 status; // this is aligned at offset 0 SA( u32 ) value; // this is aligned at offset 1 ( can cause a bus error ) }; #pragma pack() void foo( Packed_Structure * pk ) { u8 var1 = pk->status; u32 var2 = pk->value; // this can no longer cause a bus error } #endif // // The data type 'SA( u32 )' in the above structure uses the 'safe_access' method to // ensure that bus errors don't occur when the data is being accessed on the fragile // platform. Since the network structures are typically packed, and possibly aligned // on addresses that can cause bus errors, the structure's data elements should use // versions of data elements that are 'access safe'. //--------------------------------------------------------------------------------------- template< typename Ty > struct safe_access_wrapper { Ty m_data; // contains the data that is possibly misaligned operator Ty() const { return safe_access( m_data ); } const Ty & operator = ( const Ty & value ) { safe_variable_copy< sizeof( Ty ) >( &m_data, &value ); return m_data; } }; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------------------------- // SAFE() Macro ( Safe Access ) // SA() Macro ( Safe Access Type Wrapper ) // // The SA() macro is used to wrap structure elements inside packed structures that may // cause bus errors when accessed, like on the SPARC processors. // Example of usage: // // #pragma pack(1) // struct Packed_Structure // { // u8 byte_aligned; // accessing this never causes a bus error // SA( u32 ) mis_aligned; // accessing this can no longer cause a bus error // }; // // The SAFE() macro is used to wrap access to basic data types that cause bus errors. // Example of usage: // // void foo( Packed_Structure * pk ) // { // u32 var1 = pk->variable; // this may cause a bus error on the SPARC chip // u32 var2 = SAFE( pk->variable ); // this can no longer cause a bus error // } //--------------------------------------------------------------------------------------- #if CPU_SPARC #define SA( type ) safe_access_wrapper< type > #define SAFE( argument ) safe_access( argument ) #else #define SA( type ) type #define SAFE( argument ) ( argument ) #endif #endif // #ifndef __SAFE_ACCESS_H__ // //--------------------------------------------------------------------------------------- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++