__attribute__

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
Post Reply
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

__attribute__

Post by BB Hood »

I am having trouble getting PLX lesson 30(NeHe lesson 31) to work on the Dreamcast. I ported it and was able to get it to work on the NullDC emulator but when I load it into the Dreamcast it immediately closes because it can't load the milkshape model. I have tracked down the problem to the following code. I never had to use pragma or __attribute__ plus one would probably need to know a lot about the compiler to use those. I've tried doing my research here: http://www.delorie.com/gnu/docs/gcc/gcc_62.html and tried different things for the __attribute__ section since I know (at least I think I do) that __GNUC__ is defined so it is the section of code I have to worry about. Nothing worked. I've also tried removing all that stuff and just have the plain structs but then it didn't work for NullDC and Dreamcast. Anybody have any idea what I should put there besides "packed"? If not, could I modify the whole(model loading) source so I would not need __attribute__? Any help would be great.

Code: Select all

/* 
	MS3D STRUCTURES 
*/

// byte-align structures
#ifdef _MSC_VER
#	pragma pack( push, packing )
#	pragma pack( 1 )
#	define PACK_STRUCT
#elif defined( __GNUC__ )
#	define PACK_STRUCT	__attribute__((packed))
#else
#	error you must byte-align these structures with the appropriate compiler directives
#endif

typedef unsigned char byte;
typedef unsigned short word;

// File header
struct MS3DHeader
{
	char m_ID[10];
	int m_version;
} PACK_STRUCT;

// Vertex information
struct MS3DVertex
{
	byte m_flags;
	float m_vertex[3];
	char m_boneID;
	byte m_refCount;
} PACK_STRUCT;

// Triangle information
struct MS3DTriangle
{
	word m_flags;
	word m_vertexIndices[3];
	float m_vertexNormals[3][3];
	float m_s[3], m_t[3];
	byte m_smoothingGroup;
	byte m_groupIndex;
} PACK_STRUCT;

// Material information
struct MS3DMaterial
{
    char m_name[32];
    float m_ambient[4];
    float m_diffuse[4];
    float m_specular[4];
    float m_emissive[4];
    float m_shininess;	// 0.0f - 128.0f
    float m_transparency;	// 0.0f - 1.0f
    byte m_mode;	// 0, 1, 2 is unused now
    char m_texture[128];
    char m_alphamap[128];
} PACK_STRUCT;

//	Joint information
struct MS3DJoint
{
	byte m_flags;
	char m_name[32];
	char m_parentName[32];
	float m_rotation[3];
	float m_translation[3];
	word m_numRotationKeyframes;
	word m_numTranslationKeyframes;
} PACK_STRUCT;

// Keyframe data
struct MS3DKeyframe
{
	float m_time;
	float m_parameter[3];
} PACK_STRUCT;

// Default alignment 
#ifdef _MSC_VER
#	pragma pack( pop, packing )
#endif

#undef PACK_STRUCT
If you want to test out things yourself you can find all of the source code here: https://sourceforge.net/projects/parallaxnehe/files/. Click on lesson 30.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5666
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: __attribute__

Post by BlueCrab »

The __attribute__((packed)) attribute on a structure tells GCC to ignore the normal alignment that the members would have, and instead put them in exactly the order specified, in exactly the place specified. Its absolutely required if you're trying to read binary data from a file in the way that that example is probably doing.

If you wanted to modify it so that it didn't require the __attribute__((packed)) stuff, you'd have to load each individual member separately, which would be a pain. However, if GCC isn't doing things right, that may be what you will end up having to do.

That said, I've never seen GCC fail to do packing right on structures, and such things are used in various parts of KOS and seem to work just fine.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: __attribute__

Post by BB Hood »

I think you may be right about it never failing. This time I ran dc-tool-ip and sent the output to log.txt file. This is the output:

Code: Select all

--
pvr: enabling vertical scaling for non-VGA

Unhandled exception: PC 8c010ebc, code 1, evt 00e0
 R0-R7: 8c11c020 00000000 8c03c2e0 8c0cfe94 8c11bf20 00000000 8c11bf40 29d4ca6d
 R8-R15: 8cffff44 00000000 00000001 8c11db1d 8c11b528 00000000 8cfffe10 8cfffe10
 SR 40000000 PR 8c010eb0
-------- Stack Trace (innermost first) ---------
   8c0ab178
   (invalid frame pointer)
-------------- End Stack Trace -----------------
kernel panic: unhandled IRQ/Exception
arch: aborting the system
which means nothing to me. Researching topics in this forum ATM for the answer.

EDIT: Found a thread that could help me: viewtopic.php?f=29&t=47741&start=0&st=0 ... +exception . It should be added to the thread titled "Thread links for DC programmers"

The findings:

Code: Select all

C:\cygwin\usr\local\dc\sh-elf\bin>sh-elf-addr2line.exe -e dcp.elf 8c010ebc 8c010
eb0
/usr/local/dc/kos/projs/plx/lesson30/MilkshapeModel.cpp:175
/usr/local/dc/kos/projs/plx/lesson30/MilkshapeModel.cpp:170
 
   typedef unsigned short word;
        ...
   int nGroups = *( word* )pPtr;
	m_numMeshes = nGroups;
	m_pMeshes = new Mesh[nGroups];
	pPtr += sizeof( word );

   for ( i = 0; i < nGroups; i++ )                     //<<<LINE 170
	{
		pPtr += sizeof( byte );	// flags
		pPtr += 32;				// name
		
		word nTriangles = *( word* )pPtr;                //<<<LINE 175

		pPtr += sizeof( word );
		int *pTriangleIndices = new int[nTriangles];
		for ( int j = 0; j < nTriangles; j++ )
		{
			pTriangleIndices[j] = *( word* )pPtr;
			pPtr += sizeof( word );
		}

		char materialIndex = *( char* )pPtr;
		pPtr += sizeof( char );
	
		m_pMeshes[i].m_materialIndex = materialIndex;
		m_pMeshes[i].m_numTriangles = nTriangles;
		m_pMeshes[i].m_pTriangleIndices = pTriangleIndices;
	}
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5666
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: __attribute__

Post by BlueCrab »

That actually is more helpful. What it looks like to me is that the code is doing an unaligned memory access because of the pointer dereference there on line 175, and that unhandled exception seems to agree there. On the SH4, all 16-bit memory accesses must be aligned on 16-bit boundaries, and 32-bit memory accesses on 32-bit boundaries, or you will get an exception.

The fact that the pPtr is being incremented by 33 will make it unaligned for the access to the word-sized (16-bit) entry that its trying to read on line 175.

The easiest way to fix that would be to make a function for reading words (16-bit) as individual bytes and to call them instead of doing that nasty pointer crap.

By the way it looks, I'm guessing that the models are stored with little-endian byte ordering, so... this should be an appropriate function to read a word from a position (noting that I'm half asleep right now and haven't actually tried to compile this -- its straight from my head here... also, overly casted for clarity):

Code: Select all

static inline word read_word(const byte *ptr) {
    return ((word)(*ptr)) | (((word) *(ptr + 1)) << 8);
}
If you add that function to your file, and replace all the lines that are like:

Code: Select all

blah = *(word *)pPtr;
With:

Code: Select all

blah = read_word(pPtr);
You shouldn't end up with that unhandled exception any more.

I'd recommend replacing all of the things like that (with the word * dereferencing), just for safety... Even if some do work right at the moment.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: __attribute__

Post by BB Hood »

Wow, I would never figured that out. Thanks again BlueCrab.

btw, I got errors but the following code worked. For anybody who has the same problem.

Code: Select all

static inline word read_word(const char *ptr) {  // changed from byte to char
    return ((word)(*ptr)) | (((word) *(ptr + 1)) << 8);
}
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5666
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: __attribute__

Post by BlueCrab »

BB Hood wrote:Wow, I would never figured that out. Thanks again BlueCrab.

btw, I got errors but the following code worked. For anybody who has the same problem.

Code: Select all

static inline word read_word(const char *ptr) {  // changed from byte to char
    return ((word)(*ptr)) | (((word) *(ptr + 1)) << 8);
}
I figured the typedefs you posted earlier on were still in effect. Technically, you should be using an unsigned char there, not just a char, since sometimes char is signed.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: __attribute__

Post by BB Hood »

I would get an error since

Code: Select all

const char *pPtr = pBuffer;

MilkshapeModel.cpp:141: error: invalid conversion from `const char*' to `const u
nsigned char*'
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5666
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: __attribute__

Post by BlueCrab »

The pPtr, In my opinion, should probably be an unsigned char *, not a char *. But use whatever works for you. :wink:
Post Reply