I'm using MinGW, but I can use gdb to provide debugging data (and that'll likely be more useful anyway, since you're using Linux).
First, here's my current makefle:
all: stageview
stageview: stageview.o
	gcc $< -o $@ -L/usr/lib -lopengl32 -lglu32 -lglut32 -lstdc++
stageview.o: stageview.cpp
	gcc $< -c -o $@ -I/usr/include -g
And here's my current stageview.cpp:
// System
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// STL
#include <string>
#include <cassert>
// GLUT
#include <glut/glut.h>
// OpenGL
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glext.h>
using namespace std;
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned long int u32;
typedef signed char s8;
typedef signed short int s16;
typedef signed long int s32;
// utility functions
u16 get_u16le(void const * const buf)
{
	return ((u8*)buf)[0] | (((u8*)buf)[1]<<8);
}
u32 get_u32le(void const * const buf)
{
	return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16) | (((u8*)buf)[3]<<24);
}
int load( const string & name, void ** data )
{
        size_t size = 0;
        *data = NULL;
        int fd = open( name.c_str(), O_RDONLY, 0 );
        if (fd >= 0) {
                struct stat sb;
                if ( fstat( fd, &sb ) >= 0) {
                        assert( sb.st_size > 0 );
                        void *tmp = malloc( sb.st_size );
                        if ( tmp!=NULL ) {
                                if (read( fd, tmp, sb.st_size ) == sb.st_size) {
                                        *data = tmp;
                                        size = sb.st_size;
                                } else {
                                        free(tmp);
                                }
                        }
                }
                close( fd );
        }
        return size;
}
int load_lzs(const string & name, void ** data )
{
	// read compressed data
	u8 *buf;
	int tsize = load( name, (void**)&buf );
	int isize = get_u32le(buf) + 4;
	
	if (isize != tsize) {
		free(buf);
		*data = NULL;
		return 0;
	}
	
	// decompress;
	int osize = (isize + 255) & ~255;
	u8 * obuf = (u8 *)malloc(osize);
	int iofs = 4, oofs = 0;
	u8 cmd=0, bit=0;
	while (iofs < isize) {
		if (bit == 0) {
			cmd = buf[iofs++];
			bit = 8;
		}
		if (cmd&1) {
			obuf[oofs++]=buf[iofs++];
			if (oofs==osize) {
				osize+=256;
				obuf = (u8*)realloc(obuf, osize);
			}
		} else {
			u8 a = buf[iofs++];
			u8 b = buf[iofs++];
			u16 o = a | ((b&0xF0)<<4);
			u8 len = (b&0xF)+3;
			
			int rofs =  oofs - ((oofs - 18 - o) & 0xFFF);
			for (int j=0; j<len; j++) {
				if (rofs < 0) {
					obuf[oofs++]=0;
				} else {
					obuf[oofs++]=obuf[rofs];
				}
				if (oofs==osize) {
					osize+=256;
					obuf = (u8*)realloc(obuf, osize);
				}
				rofs++;
			}
		}
		cmd>>=1;
		bit--;
	}
	free( buf );
	
	*data = obuf;
	return oofs;
}
// Background loading and storage
struct Vertex {
	s16 x, y, z;
	s16 u, v;
};
struct Element {
	u16 a, b, c, s; // s = shader
};
struct Mesh {
	int texture;
	int element_start;
	int element_count;
};
struct Shader {
	int texture;
	int palette;
};
struct Background {
	int vertex_count;
	Vertex *vertex;
	int element_count;
	Element *element;
	int *indexbuffer;
	int shader_count;
	Shader *shader;
	GLuint *textures;
	int mesh_count;
	Mesh *mesh;
};
int
add_vertex(Background *bg, s16 x, s16 y, s16 z, u8 u, u8 v)
{
	for (int i=0; i<bg->vertex_count; i++) {
		if (bg->vertex[i].x == x && bg->vertex[i].y == y && bg->vertex[i].z == z && bg->vertex[i].u == u && bg->vertex[i].v == v) {
			return i;
		}
	}
	
	int idx = bg->vertex_count++;
	bg->vertex = (Vertex *)realloc(bg->vertex, bg->vertex_count * sizeof(Vertex));
	bg->vertex[idx].x = x;
	bg->vertex[idx].y = y;
	bg->vertex[idx].z = z;
	bg->vertex[idx].u = u;
	bg->vertex[idx].v = v;
	return idx;
}
int 
add_triangle(Background *bg, u16 a, u16 b, u16 c, u16 s)
{
	int idx = bg->element_count++;
	bg->element = (Element*)realloc(bg->element, bg->element_count * sizeof(Element));
	bg->element[idx].a = a;
	bg->element[idx].b = b;
	bg->element[idx].c = c;
	bg->element[idx].s = s;
	return idx;
}
int
add_shader(Background *bg, int texture, int palette)
{
	for (int i=0; i<bg->shader_count; i++) {
		if (bg->shader[i].texture == texture && bg->shader[i].palette == palette) {
			return i;
		}
	}
	
	int idx = bg->shader_count++;
	bg->shader = (Shader *)realloc(bg->shader, bg->shader_count * sizeof(Shader));
	bg->shader[idx].texture = texture;
	bg->shader[idx].palette = palette;
	
	return idx;
}
void
load_background(const string & filename, Background *bg)
{
	bg->vertex_count = 0;
	bg->vertex = NULL;
	bg->element_count = 0;
	bg->element = NULL;
	bg->textures = NULL;
	bg->shader_count = 0;
	bg->shader = NULL;
	bg->mesh_count = 0;
	bg->mesh = NULL;
	
	u8 * data;
	int size = load_lzs(filename, (void**)&data);
	int num_pointer = get_u32le(data);
	
	// background texture
	int texdata = get_u32le(data + num_pointer * 4);
	int npal = get_u16le(data + texdata + 18);
	int paldata_size = get_u32le(data+texdata+8);
	int pal_ofs = texdata + 20;
	int picdata_size = get_u32le(data+texdata+8+paldata_size);
	int pic_ofs = texdata + 20 + npal*512 + 12;
	
	int xsize = get_u16le(data+pic_ofs-4)*2;
	int ysize = get_u16le(data+pic_ofs-2);
	
	// convert mesh data
	for (int i=1; i<num_pointer-1; i++) {
		int base = get_u32le(data + 4 + i * 4);
		
		// triangles
		int triangle_offset = base + 4 + get_u32le(data + base);
		int num_triangles = get_u16le(data + triangle_offset);
		int mesh_tri_flags = get_u16le(data + triangle_offset + 2);
		
		int texture_idx = ((mesh_tri_flags & 0x0E)-6) / 2;
		for (int j=0; j<num_triangles; j++) {
			int point[3];
			int ofs = triangle_offset + 4 + j * 16;
			for (int k=0; k<3; k++) {
				int p = get_u16le(data + ofs + k * 2) + base + 4;
				s16 x =  ((s16)get_u16le(data + p + 0*2));
				s16 y = -((s16)get_u16le(data + p + 1*2));
				s16 z =  ((s16)get_u16le(data + p + 2*2));
				const int uv_offsets[3] = { 8, 12, 14 };
				u8 u = data[ofs + uv_offsets[k] + 0];
				u8 v = data[ofs + uv_offsets[k] + 1];
				point[k] = add_vertex(bg, x,y,z,u,v);
			}
			u16 flags1 = get_u16le(data + ofs + 6);
			u16 flags2 = get_u16le(data + ofs + 10);
			
			int palette_idx = (flags2 >> 6) & 7;
			int shader_idx = add_shader(bg, texture_idx, palette_idx);
			
			add_triangle(bg, point[0], point[1], point[2], shader_idx);
		}
		
		// quads
		int quad_offset = triangle_offset + 4 + num_triangles * 16;
		int num_quads = get_u16le(data + quad_offset);
		int mesh_quad_flags = get_u16le(data + quad_offset + 2);
		for (int j=0; j<num_quads; j++) {
			int point[4];
			int ofs = quad_offset + 4 + j * 20;
			for (int k=0; k<4; k++) {
				int p = get_u16le(data + ofs + k * 2) + base + 4;
				s16 x =  ((s16)get_u16le(data + p + 0 * 2));
				s16 y = -((s16)get_u16le(data + p + 1 * 2));
				s16 z =  ((s16)get_u16le(data + p + 2 * 2));
				
				const int uv_offsets[4] = { 8, 12, 14, 16 };
				u8 u = data[ofs + uv_offsets[k] + 0];
				u8 v = data[ofs + uv_offsets[k] + 1];
				point[k] = add_vertex(bg, x,y,z,u,v);
			}
			u16 flags1 = get_u16le(data + ofs + 18);
			u16 flags2 = get_u16le(data + ofs + 10);
			int palette_idx = (flags2 >> 6) & 7;
			int shader_idx = add_shader(bg, texture_idx, palette_idx);
			
			add_triangle(bg, point[0], point[1], point[2], shader_idx);
			add_triangle(bg, point[3], point[2], point[1], shader_idx);
		}
	}
	
	// build meshes
	bg->indexbuffer = (int*)malloc(bg->element_count * 3 * sizeof(int));
	int cur_mesh = 0;
	for (int i=0; i<bg->element_count; i++) {
		bg->indexbuffer[i * 3 + 0] = bg->element[i].a;
		bg->indexbuffer[i * 3 + 1] = bg->element[i].b;
		bg->indexbuffer[i * 3 + 2] = bg->element[i].c;
		
		if (bg->mesh_count > 0 && bg->mesh[cur_mesh].texture == bg->element[i].s) {
			bg->mesh[cur_mesh].element_count++;
		} else {
			cur_mesh = bg->mesh_count++;
			bg->mesh = (Mesh*)realloc(bg->mesh, bg->mesh_count * sizeof(Mesh));
			bg->mesh[cur_mesh].texture = bg->element[i].s;
			bg->mesh[cur_mesh].element_start = i*3;
			bg->mesh[cur_mesh].element_count = 1;
		}
	}
	
	// build required textures
	struct RGBA {
		u8 r, g, b, a;
	};
	
	RGBA *clut = (RGBA*)malloc(sizeof(RGBA) * 256 * (npal));
	for (int j = 0; j < npal; j++) {
		for (int i=0; i<256; i++) {
			u16 col = (data[i*2 + pal_ofs + j*512 + 1]<<8) | data[i*2 + pal_ofs + j * 512];
			clut[i+j*256].r = (((col      ) & 31) * 255 + 15) / 31;
			clut[i+j*256].g = (((col >>  5) & 31) * 255 + 15) / 31;
			clut[i+j*256].b = (((col >> 10) & 31) * 255 + 15) / 31;
			clut[i+j*256].a = ((col & 0x8000) || (col == 0)) ? 0 : 255;
		}
	}
	
	bg->textures = (GLuint*)malloc(sizeof(GLuint) * bg->shader_count);
	glGenTextures( bg->shader_count, bg->textures);
	RGBA *texture = (RGBA*)malloc(sizeof(RGBA) * 256 * 256);
	for (int i=0; i<bg->shader_count; i++) {
		// build
#if 1
		if ( bg->shader[i].palette >= npal ) {
			printf("%i %i\n", bg->shader[i].palette, npal);
			bg->shader[i].palette = 0;
		}
#endif
		for (int y=0; y<256; y++) {
			for (int x=0; x<256; x++) {
				texture[y*256+x] = clut[data[pic_ofs + y * xsize + x + bg->shader[i].texture * 256] + bg->shader[i].palette * 256];
			}
		}
		
		// copy to GL
		glBindTexture( GL_TEXTURE_2D, bg->textures[i]);
#if 0
		// blocky
		glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture);
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
#else
		// interpolated
		gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, 256, 256, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture);
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
#endif
	}
	free(texture);
	free(clut);
	free(data);
}
// GLUT and OpenGL stuff
Background battle;
int rot_y;
int rot_x;
void ReshapeWindowFunc(int width, int height)
{
	const double kFOVy = 0.57735;
	const double kZNear = 0.1;
	
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	GLdouble aspect = ((GLfloat)width / (GLfloat)height) * (kZNear * kFOVy);
	glFrustum(-aspect, aspect, -(kZNear * kFOVy), (kZNear * kFOVy), kZNear, 1000.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
void MainRenderLoop(void)
{
	// render
	glClearColor(0, 0, 0, 1.00);
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable( GL_DEPTH_TEST );
	glDepthFunc( GL_LEQUAL );			
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER, 1.0f/255.0f);
	glEnable( GL_TEXTURE_2D );
	glEnable( GL_CULL_FACE );
	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
        glDisable( GL_LIGHTING );
	glDisable( GL_BLEND );
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glRotatef( (float)rot_x * 360.0f / 256.0f, 1.0f, 0.0f, 0.0f );
	glRotatef( (float)rot_y * 360.0f / 256.0f, 0.0f, 1.0f, 0.0f );
	glTranslatef( 0, -16, 0);
	glScalef( 1.0f/256.0f, 1.0f/256.0f, 1.0f/256.0f );
	
	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glScalef(1.0f/256.0f, 1.0f/256.0f, 0);
	glTranslatef( 0.5f, 0.5f, 0);
	
	glEnableClientState( GL_VERTEX_ARRAY );
	glEnableClientState( GL_TEXTURE_COORD_ARRAY );
	
	glVertexPointer( 3, GL_SHORT, sizeof(Vertex), &(battle.vertex[0].x) );
	glTexCoordPointer( 2, GL_SHORT, sizeof(Vertex), &(battle.vertex[0].u) );
	for (int i = 0; i < battle.mesh_count; i++) {
		glBindTexture(GL_TEXTURE_2D, battle.textures[battle.mesh[i].texture]);
		glDrawElements(GL_TRIANGLES, battle.mesh[i].element_count * 3, GL_UNSIGNED_INT, battle.indexbuffer + battle.mesh[i].element_start);
	}
	
	glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	glDisableClientState( GL_VERTEX_ARRAY );
	
	glFlush();
}
void SpecialHandler(int key, int x, int y)
{
	switch (key) {
		case GLUT_KEY_UP:
			rot_x -= 4;
			if (rot_x < -64) { 
				rot_x = -64; 
			}
			break;
		case GLUT_KEY_DOWN:
			rot_x += 4;
			if (rot_x > 64) { 
				rot_x = 64; 
			}
			break;
		case GLUT_KEY_LEFT:
			rot_y -= 5;
			break;
		case GLUT_KEY_RIGHT:
			rot_y += 5;
			break;
	}
	glutPostRedisplay();
}
void KeyboardHandler(unsigned char key, int x, int y)
{
	switch (key) {
		case 27:
			exit(0);
			break;
	}
}
int main(int argc, char *argv[]) 
{
	if (argc != 2) {
		fprintf(stderr, "stageview <stage.lzs>\n");
	} else {
// get current directory
		char cwd[1024];
		getcwd(cwd, sizeof(cwd));
              string path;
		if (argv[1][0] != 0 && argv[1][0] != '/' && argv[1][1] != 0 && argv[1][1] != ':' && argv[1][2] != 0 && argv[1][2] != '\\') {
			path = string(cwd) + "/";
		}
		// init opengl and glut
		glutInit(&argc, (char **) argv);
		glutInitWindowSize(640, 480);
		glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
		glutCreateWindow(argv[0]);
		glutDisplayFunc(MainRenderLoop);
		glutIdleFunc(MainRenderLoop);
		glutReshapeFunc(ReshapeWindowFunc);
		glutKeyboardFunc(KeyboardHandler);
		glutSpecialFunc(SpecialHandler);
				
		// load data
		load_background(path + argv[1], &battle);
		
		rot_y = rot_x = 0;
		
		// main (this will never return)
		glutMainLoop();
	}
	return 0;
}
gdb using STAGE04.LZS (since you mentioned that specific file, though the outcome is the same regardless of which file I use...even if the file doesn't exist or isn't the right format):
[USERNAME OMITTED]@[HOST OMITTED] ~
$ gdb stageview
GNU gdb (GDB) 7.4
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\stageview.exe...done.
(gdb) r C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\STAGE04.LZS
Starting program: C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\STAGE04.LZS
[New Thread 848.0xc08]
Program received signal SIGSEGV, Segmentation fault.
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
45              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)
| (((u8*)buf)[3]<<24);
(gdb) where
#0  0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
#1  0x00401557 in load_lzs (name=..., data=0x22fa30) at stageview.cpp:77
#2  0x00401ad0 in load_background (filename=..., bg=0x40c020)
    at stageview.cpp:228
#3  0x00402e49 in main (argc=2, argv=0x3e26f8) at stageview.cpp:502
(gdb)
So, it seems to dislike the array for get_u32le.