Rewrite the assembly pipeline.

This patch uses SmxBuilder from spcomp2 to replace the old assemble()
pipeline. Instead of generating into an old AMX structure, and then
decoding that into SMX, we now directly generate into SMX. This greatly
simplifies code generation and smx building.
This commit is contained in:
David Anderson 2014-08-23 01:57:13 -07:00
parent 7a51d5d549
commit c4056aea5d
17 changed files with 961 additions and 1924 deletions

View File

@ -339,6 +339,25 @@ class StorageBuffer
};
};
template <typename T>
class SaveAndSet
{
public:
SaveAndSet(T *location, const T &value)
: location_(location),
old_(*location)
{
*location_ = value;
}
~SaveAndSet() {
*location_ = old_;
}
private:
T *location_;
T old_;
};
#if defined(_MSC_VER)
# define KE_SIZET_FMT "%Iu"
#elif defined(__GNUC__)

View File

@ -45,6 +45,7 @@ compiler.includes += [
os.path.join(builder.sourcePath, 'public', 'amtl'),
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
os.path.join(builder.sourcePath, 'sourcepawn', 'compiler'),
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
os.path.join(builder.buildPath, 'includes'),
os.path.join(builder.buildPath, builder.buildFolder),
]
@ -54,7 +55,8 @@ if compiler.cc.behavior == 'gcc':
compiler.cflags += ['-Wno-format']
compiler.c_only_flags += ['-std=c99']
if builder.target_platform == 'linux':
compiler.postlink += ['-lgcc', '-lm']
compiler.postlink += ['-lm']
compiler.postlink += ['-lstdc++']
elif compiler.cc.behavior == 'msvc':
compiler.linkflags.remove('/SUBSYSTEM:WINDOWS')
compiler.linkflags.append('/SUBSYSTEM:CONSOLE')
@ -95,7 +97,7 @@ binary.sources += [
'scstate.cpp',
'sctracker.cpp',
'scvars.cpp',
'sp_file.cpp',
'smx-builder.cpp',
'zlib/adler32.c',
'zlib/compress.c',
'zlib/crc32.c',

View File

@ -1,4 +1,4 @@
// vim: set sts=8 ts=4 sw=4 tw=99 noet:
// vim: set sts=8 ts=2 sw=2 tw=99 noet:
/* LIBPAWNC.C
*
* A "glue file" for building the Pawn compiler as a DLL or shared library.
@ -341,42 +341,3 @@ char *pc_readasm(void *handle, char *string, int maxchars)
{
return mfgets((MEMFILE*)handle,string,maxchars);
}
extern memfile_t *bin_file;
/* Should return a pointer, which is used as a "magic cookie" to all I/O
* functions; return NULL for failure.
*/
void *pc_openbin(char *filename)
{
return memfile_creat(filename, 1);
}
void pc_closebin(void *handle,int deletefile)
{
if (deletefile) {
memfile_destroy((memfile_t *)handle);
bin_file = NULL;
} else {
bin_file = (memfile_t *)handle;
}
}
/* pc_resetbin()
* Can seek to any location in the file.
* The offset is always from the start of the file.
*/
void pc_resetbin(void *handle,long offset)
{
memfile_seek((memfile_t *)handle, offset);
}
int pc_writebin(void *handle,void *buffer,int size)
{
return memfile_write((memfile_t *)handle, buffer, size);
}
long pc_lengthbin(void *handle)
{
return memfile_tell((memfile_t *)handle);
}

View File

@ -0,0 +1,94 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2012-2014 AlliedModders LLC, David Anderson
//
// This file is part of SourcePawn.
//
// SourcePawn is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
#ifndef _include_sp_memory_buffer_h_
#define _include_sp_memory_buffer_h_
#include <stdio.h>
#include <am-utility.h>
#include "smx-builder.h"
class MemoryBuffer : public ke::ISmxBuffer
{
static const size_t kDefaultSize = 4096;
public:
MemoryBuffer() {
buffer_ = (uint8_t *)calloc(kDefaultSize, 1);
pos_ = buffer_;
end_ = buffer_ + kDefaultSize;
}
~MemoryBuffer() {
free(buffer_);
}
bool write(const void *bytes, size_t len) KE_OVERRIDE {
if (pos_ + len > end_)
grow(len);
memcpy(pos_, bytes, len);
pos_ += len;
return true;
}
size_t pos() const KE_OVERRIDE {
return pos_ - buffer_;
}
uint8_t *bytes() const {
return buffer_;
}
size_t size() const {
return pos();
}
void rewind(size_t newpos) {
assert(newpos < pos());
pos_ = buffer_ + newpos;
}
private:
void grow(size_t len) {
if (!ke::IsUintPtrAddSafe(pos(), len)) {
fprintf(stderr, "Allocation overflow!\n");
abort();
}
size_t new_maxsize = end_ - buffer_;
while (pos() + len > new_maxsize) {
if (!ke::IsUintPtrMultiplySafe(new_maxsize, 2)) {
fprintf(stderr, "Allocation overflow!\n");
abort();
}
new_maxsize *= 2;
}
uint8_t *newbuffer = (uint8_t *)realloc(buffer_, new_maxsize);
if (!newbuffer) {
fprintf(stderr, "Out of memory!\n");
abort();
}
pos_ = newbuffer + (pos_ - buffer_);
end_ = newbuffer + new_maxsize;
buffer_ = newbuffer;
}
private:
uint8_t *buffer_;
uint8_t *pos_;
uint8_t *end_;
};
#endif // _include_sp_memory_buffer_h_

View File

@ -3,557 +3,19 @@
#include <assert.h>
#include <string.h>
#include "memfile.h"
#include "sp_file.h"
#include "amx.h"
#include "amxdbg.h"
#include "osdefs.h"
#include "zlib/zlib.h"
#if defined LINUX || defined DARWIN
#include <unistd.h>
#elif defined WIN32
#include <io.h>
#endif
enum FileSections
{
FS_Code, /* required */
FS_Data, /* required */
FS_Publics,
FS_Pubvars,
FS_Natives,
FS_Nametable, /* required */
FS_DbgFile,
FS_DbgSymbol,
FS_DbgLine,
FS_DbgTags,
FS_DbgNatives,
FS_DbgAutomaton,
FS_DbgState,
FS_DbgStrings,
FS_DbgInfo,
FS_Tags,
/* --- */
FS_Number,
};
int pc_printf(const char *message,...);
int pc_compile(int argc, char **argv);
void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf);
memfile_t *bin_file = NULL;
jmp_buf brkout;
#define sARGS_MAX 32 /* number of arguments a function can have, max */
#define sDIMEN_MAX 4 /* maximum number of array dimensions */
typedef struct t_arg_s
{
uint8_t ident;
int16_t tag;
char *name;
uint16_t dimcount;
sp_fdbg_arraydim_t dims[sDIMEN_MAX];
} t_arg;
typedef struct t_native_s
{
char *name;
int16_t ret_tag;
uint16_t num_args;
t_arg args[sARGS_MAX];
} t_native;
t_native *native_list = NULL;
#include "sc.h"
int main(int argc, char *argv[])
{
if (pc_compile(argc,argv) != 0)
return 1;
AMX_HEADER *hdr;
AMX_DBG_HDR *dbg = NULL;
int err;
uint32_t i;
sp_file_t *spf;
memfile_t *dbgtab = NULL; //dbgcrab
unsigned char *dbgptr = NULL;
uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0};
FILE *fp;
if (bin_file == NULL)
return 0;
hdr = (AMX_HEADER *)bin_file->base;
if ((spf=spfw_create(bin_file->name, NULL)) == NULL) {
pc_printf("Error creating binary file!\n");
memfile_destroy(bin_file);
return 0;
}
if ((err=setjmp(brkout))!=0)
goto write_error;
spfw_add_section(spf, ".code");
spfw_add_section(spf, ".data");
sections[FS_Publics] = (hdr->natives - hdr->publics) / hdr->defsize;
if (sections[FS_Publics])
spfw_add_section(spf, ".publics");
sections[FS_Pubvars] = (hdr->tags - hdr->pubvars) / hdr->defsize;
if (sections[FS_Pubvars])
spfw_add_section(spf, ".pubvars");
sections[FS_Natives] = (hdr->libraries - hdr->natives) / hdr->defsize;
if (sections[FS_Natives])
spfw_add_section(spf, ".natives");
sections[FS_Tags] = (hdr->nametable - hdr->tags) / hdr->defsize;
if (sections[FS_Tags])
spfw_add_section(spf, ".tags");
spfw_add_section(spf, ".names");
if (hdr->flags & AMX_FLAG_DEBUG) {
dbg = (AMX_DBG_HDR *)((unsigned char *)hdr + hdr->size);
if (dbg->magic != AMX_DBG_MAGIC) {
pc_printf("Error reading AMX_DBG_HDR, debug data will not be written.");
} else {
dbgtab = memfile_creat("", 512);
dbgptr = (unsigned char *)dbg + sizeof(AMX_DBG_HDR);
if ((sections[FS_DbgNatives] = sections[FS_Natives]) > 0)
spfw_add_section(spf, ".dbg.natives");
if (dbg->files) {
spfw_add_section(spf, ".dbg.files");
sections[FS_DbgFile] = dbg->files;
}
if (dbg->lines) {
spfw_add_section(spf, ".dbg.lines");
sections[FS_DbgLine] = dbg->lines;
}
if (dbg->symbols) {
spfw_add_section(spf, ".dbg.symbols");
sections[FS_DbgSymbol] = dbg->symbols;
}
sections[FS_DbgInfo] = 1;
sections[FS_DbgStrings] = 1;
spfw_add_section(spf, ".dbg.info");
spfw_add_section(spf, ".dbg.strings");
}
}
spfw_finalize_header(spf);
/**
* Begin writing each of our known tables out
*/
if (sections[FS_Code]) {
sp_file_code_t cod;
unsigned char *cbase;
cod.cellsize = sizeof(cell);
cod.codesize = hdr->dat - hdr->cod;
cod.codeversion = hdr->amx_version;
cod.flags = 0;
if (hdr->flags & AMX_FLAG_DEBUG)
{
cod.flags |= SP_FLAG_DEBUG;
}
cod.code = sizeof(cod);
cod.main = hdr->cip;
/* write the code */
cbase = (unsigned char *)hdr + hdr->cod;
sfwrite(&cod, sizeof(cod), 1, spf);
sfwrite(cbase, cod.codesize, 1, spf);
spfw_next_section(spf);
}
if (sections[FS_Data]) {
sp_file_data_t dat;
unsigned char *dbase = (unsigned char *)hdr + hdr->dat;
dat.datasize = hdr->hea - hdr->dat;
dat.memsize = hdr->stp;
dat.data = sizeof(dat);
/* write header */
sfwrite(&dat, sizeof(dat), 1, spf);
if (dat.datasize) {
/* write data */
sfwrite(dbase, dat.datasize, 1, spf);
}
spfw_next_section(spf);
}
if (sections[FS_Publics]) {
sp_file_publics_t *pbtbl;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t publics = sections[FS_Publics];
pbtbl = (sp_file_publics_t *)malloc(sizeof(sp_file_publics_t) * publics);
stubptr = (unsigned char *)hdr + hdr->publics;
for (i=0; i<publics; i++) {
stub = (AMX_FUNCSTUBNT *)stubptr;
pbtbl[i].address = stub->address;
pbtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (publics)
sfwrite(pbtbl, sizeof(sp_file_publics_t), publics, spf);
free(pbtbl);
spfw_next_section(spf);
}
if (sections[FS_Pubvars]) {
sp_file_pubvars_t *pbvars;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t pubvars = sections[FS_Pubvars];
pbvars = (sp_file_pubvars_t *)malloc(sizeof(sp_file_pubvars_t) * pubvars);
stubptr = (unsigned char *)hdr + hdr->pubvars;
for (i=0; i<pubvars; i++) {
stub = (AMX_FUNCSTUBNT *)stubptr;
pbvars[i].address = stub->address;
pbvars[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (pubvars)
sfwrite(pbvars, sizeof(sp_file_pubvars_t), pubvars, spf);
free(pbvars);
spfw_next_section(spf);
}
if (sections[FS_Natives]) {
sp_file_natives_t *nvtbl;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize;
nvtbl = (sp_file_natives_t *)malloc(sizeof(sp_file_natives_t) * natives);
stubptr = (unsigned char *)hdr + hdr->natives;
for (i=0; i<natives; i++) {
stub = (AMX_FUNCSTUBNT *)stubptr;
nvtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (natives) {
sfwrite(nvtbl, sizeof(sp_file_natives_t), natives, spf);
}
free(nvtbl);
spfw_next_section(spf);
}
if (sections[FS_Tags]) {
uint32_t numTags = (uint32_t)sections[FS_Tags];
AMX_FUNCSTUBNT *stub;
sp_file_tag_t tag;
for (i=0; i<numTags; i++) {
stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->tags + (i * hdr->defsize));
tag.tag_id = stub->address;
tag.name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
sfwrite(&tag, sizeof(sp_file_tag_t), 1, spf);
}
spfw_next_section(spf);
}
if (sections[FS_Nametable]) {
unsigned char *base;
uint32_t namelen;
/* write the entire block */
base = (unsigned char *)hdr + hdr->nametable + sizeof(uint16_t);
/**
* note - the name table will be padded to sizeof(cell) bytes.
* this may clip at most an extra three bytes in!
*/
namelen = hdr->cod - hdr->nametable;
sfwrite(base, namelen, 1, spf);
spfw_next_section(spf);
}
if (hdr->flags & AMX_FLAG_DEBUG) {
sp_fdbg_info_t info;
memset(&info, 0, sizeof(sp_fdbg_info_t));
if (sections[FS_Natives]) {
uint16_t j;
uint32_t idx;
uint32_t name;
uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize;
sfwrite(&natives, sizeof(uint32_t), 1, spf);
for (idx=0; idx<natives; idx++) {
sfwrite(&idx, sizeof(uint32_t), 1, spf);
name = (uint32_t)memfile_tell(dbgtab);
memfile_write(dbgtab, native_list[idx].name, strlen(native_list[idx].name) + 1);
sfwrite(&name, sizeof(uint32_t), 1, spf);
sfwrite(&native_list[idx].ret_tag, sizeof(int16_t), 1, spf);
sfwrite(&native_list[idx].num_args, sizeof(uint16_t), 1, spf);
/* Go through arguments */
for (j = 0; j < native_list[idx].num_args; j++) {
sfwrite(&native_list[idx].args[j].ident, sizeof(uint8_t), 1, spf);
sfwrite(&native_list[idx].args[j].tag, sizeof(int16_t), 1, spf);
sfwrite(&native_list[idx].args[j].dimcount, sizeof(uint16_t), 1, spf);
name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&name, sizeof(uint32_t), 1, spf);
memfile_write(dbgtab,
native_list[idx].args[j].name,
strlen(native_list[idx].args[j].name) + 1);
if (native_list[idx].args[j].dimcount) {
sfwrite(native_list[idx].args[j].dims,
sizeof(sp_fdbg_arraydim_t),
native_list[idx].args[j].dimcount,
spf);
}
free(native_list[idx].args[j].name);
}
free(native_list[idx].name);
}
free(native_list);
spfw_next_section(spf);
}
if (sections[FS_DbgFile]) {
uint32_t idx;
sp_fdbg_file_t dbgfile;
AMX_DBG_FILE *_ptr;
uint32_t len;
for (idx=0; idx<sections[FS_DbgFile]; idx++) {
/* get entry info */
_ptr = (AMX_DBG_FILE *)dbgptr;
len = strlen(_ptr->name);
/* store */
dbgfile.addr = _ptr->address;
dbgfile.name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&dbgfile, sizeof(sp_fdbg_file_t), 1, spf);
/* write to tab, then move to next */
memfile_write(dbgtab, _ptr->name, len + 1);
dbgptr += sizeof(AMX_DBG_FILE) + len;
info.num_files++;
}
spfw_next_section(spf);
}
if (sections[FS_DbgLine]) {
uint32_t idx;
AMX_DBG_LINE *line;
sp_fdbg_line_t dbgline;
for (idx=0; idx<sections[FS_DbgLine]; idx++) {
/* get entry info */
line = (AMX_DBG_LINE *)dbgptr;
/* store */
dbgline.addr = (uint32_t)line->address;
dbgline.line = (uint32_t)line->line;
sfwrite(&dbgline, sizeof(sp_fdbg_line_t), 1, spf);
/* move to next */
dbgptr += sizeof(AMX_DBG_LINE);
info.num_lines++;
}
spfw_next_section(spf);
}
if (sections[FS_DbgSymbol]) {
uint32_t idx;
uint32_t dnum;
AMX_DBG_SYMBOL *sym;
AMX_DBG_SYMDIM *dim;
sp_fdbg_symbol_t dbgsym;
sp_fdbg_arraydim_t dbgdim;
uint32_t len;
for (idx=0; idx<sections[FS_DbgSymbol]; idx++) {
/* get entry info */
sym = (AMX_DBG_SYMBOL *)dbgptr;
/* store */
dbgsym.addr = (int32_t)sym->address;
dbgsym.tagid = sym->tag;
dbgsym.codestart = (uint32_t)sym->codestart;
dbgsym.codeend = (uint32_t)sym->codeend;
dbgsym.dimcount = (uint16_t)sym->dim;
dbgsym.vclass = (uint8_t)sym->vclass;
dbgsym.ident = (uint8_t)sym->ident;
dbgsym.name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&dbgsym, sizeof(sp_fdbg_symbol_t), 1, spf);
/* write to tab */
len = strlen(sym->name);
memfile_write(dbgtab, sym->name, len + 1);
/* move to next */
dbgptr += sizeof(AMX_DBG_SYMBOL) + len;
/* look for any dimensions */
info.num_syms++;
for (dnum=0; dnum<dbgsym.dimcount; dnum++)
{
/* get entry info */
dim = (AMX_DBG_SYMDIM *)dbgptr;
/* store */
dbgdim.size = (uint32_t)dim->size;
dbgdim.tagid = dim->tag;
sfwrite(&dbgdim, sizeof(sp_fdbg_arraydim_t), 1, spf);
/* move to next */
dbgptr += sizeof(AMX_DBG_SYMDIM);
info.num_arrays++;
}
}
spfw_next_section(spf);
}
sfwrite(&info, sizeof(sp_fdbg_info_t), 1, spf);
spfw_next_section(spf);
if (sections[FS_DbgStrings]) {
sfwrite(dbgtab->base, sizeof(char), dbgtab->usedoffs, spf);
spfw_next_section(spf);
}
}
spfw_finalize_all(spf);
/**
* do compression
* new block for scoping only
*/
{
memfile_t *pOrig = (memfile_t *)spf->handle;
sp_file_hdr_t *pHdr;
unsigned char *proper;
size_t size;
Bytef *zcmp;
uLong disksize;
size_t header_size;
int err = Z_OK;
/* reuse this memory block! */
memfile_reset(bin_file);
/* copy tip of header */
memfile_write(bin_file, pOrig->base, sizeof(sp_file_hdr_t));
/* get pointer to header */
pHdr = (sp_file_hdr_t *)bin_file->base;
/* copy the rest of the header */
memfile_write(bin_file,
(unsigned char *)pOrig->base + sizeof(sp_file_hdr_t),
pHdr->dataoffs - sizeof(sp_file_hdr_t));
header_size = pHdr->dataoffs;
size = pHdr->imagesize - header_size;
proper = (unsigned char *)pOrig->base + header_size;
/* get initial size estimate */
disksize = compressBound(pHdr->imagesize);
pHdr->disksize = (uint32_t)disksize;
zcmp = (Bytef *)malloc(pHdr->disksize);
if ((err=compress2(zcmp,
&disksize,
(Bytef *)proper,
(uLong)size,
Z_BEST_COMPRESSION))
!= Z_OK)
{
free(zcmp);
pc_printf("Unable to compress (Z): error %d\n", err);
pc_printf("Falling back to no compression.");
memfile_write(bin_file,
proper,
size);
} else {
pHdr->disksize = (uint32_t)disksize + header_size;
pHdr->compression = SPFILE_COMPRESSION_GZ;
memfile_write(bin_file,
(unsigned char *)zcmp,
disksize);
free(zcmp);
}
}
spfw_destroy(spf);
memfile_destroy(dbgtab);
/**
* write file
*/
if ((fp=fopen(bin_file->name, "wb")) != NULL) {
fwrite(bin_file->base, bin_file->usedoffs, 1, fp);
fclose(fp);
} else {
pc_printf("Unable to open %s for writing!", bin_file->name);
}
memfile_destroy(bin_file);
return 0;
write_error:
pc_printf("Error writing to file: %s", bin_file->name);
spfw_destroy(spf);
unlink(bin_file->name);
memfile_destroy(bin_file);
memfile_destroy(dbgtab);
return 1;
return pc_compile(argc,argv);
}
void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf)
{
if (spf->funcs.fnWrite(buf, size, count, spf->handle) != count)
longjmp(brkout, 1);
}
void sp_fdbg_ntv_start(int num_natives)
{
if (num_natives == 0)
return;
native_list = (t_native *)malloc(sizeof(t_native) * num_natives);
memset(native_list, 0, sizeof(t_native) * num_natives);
}
#include "sc.h"
void sp_fdbg_ntv_hook(int index, symbol *sym)
{
int i, j;
t_native *native;
native = &native_list[index];
native->name = strdup(sym->name);
for (i = 0; i < sMAXARGS; i++) {
if (sym->dim.arglist[i].ident == 0)
break;
native->num_args++;
native->args[i].tag = sym->dim.arglist[i].tags == NULL ? 0 : sym->dim.arglist[i].tags[0];
native->args[i].name = strdup(sym->dim.arglist[i].name);
native->args[i].ident = sym->dim.arglist[i].ident;
native->args[i].dimcount = sym->dim.arglist[i].numdim;
for (j = 0; j < native->args[i].dimcount; j++) {
native->args[i].dims[j].size = sym->dim.arglist[i].dim[j];
native->args[i].dims[j].tagid = sym->dim.arglist[i].idxtag[j];
}
}
native->ret_tag = sym->tag;
}
#if defined __linux__ || defined __APPLE__
extern "C" void __cxa_pure_virtual(void)
{

View File

@ -578,13 +578,6 @@ void pc_resetasm(void *handle);
int pc_writeasm(void *handle,const char *str);
char *pc_readasm(void *handle,char *target,int maxchars);
/* output to binary (.AMX) file */
void *pc_openbin(char *filename);
void pc_closebin(void *handle,int deletefile);
void pc_resetbin(void *handle,long offset);
int pc_writebin(void *handle,void *buffer,int size);
long pc_lengthbin(void *handle); /* return the length of the file */
void sp_fdbg_ntv_start(int num_natives);
void sp_fdbg_ntv_hook(int index, symbol *sym);
@ -767,7 +760,7 @@ int error(int number,...);
void errorset(int code,int line);
/* function prototypes in SC6.C */
int assemble(void *fout,void *fin);
void assemble(const char *outname, void *fin);
/* function prototypes in SC7.C */
void stgbuffer_cleanup(void);

View File

@ -200,16 +200,11 @@ int pc_compile(int argc, char *argv[])
char incfname[_MAX_PATH];
char reportname[_MAX_PATH];
char codepage[MAXCODEPAGE+1];
FILE *binf;
void *inpfmark;
int lcl_packstr,lcl_needsemicolon,lcl_tabsize,lcl_require_newdecls;
#if !defined SC_LIGHT
int hdrsize=0;
#endif
char *ptr;
/* set global variables to their initial value */
binf=NULL;
initglobals();
errorset(sRESET,0);
errorset(sEXPRRELEASE,0);
@ -315,14 +310,6 @@ int pc_compile(int argc, char *argv[])
outf=(FILE*)pc_openasm(outfname); /* first write to assembler file (may be temporary) */
if (outf==NULL)
error(161,outfname);
/* immediately open the binary file, for other programs to check */
if (sc_asmfile || sc_listing) {
binf=NULL;
} else {
binf=(FILE*)pc_openbin(binfname);
if (binf==NULL)
error(161,binfname);
} /* if */
setconstants(); /* set predefined constants and tagnames */
for (i=0; i<skipinput; i++) /* skip lines in the input file */
if (pc_readsrc(inpf_org,pline,sLINEMAX)!=NULL)
@ -463,33 +450,27 @@ int pc_compile(int argc, char *argv[])
cleanup:
if (inpf!=NULL) /* main source file is not closed, do it now */
pc_closesrc(inpf);
/* write the binary file (the file is already open) */
// Write the binary file.
if (!(sc_asmfile || sc_listing) && errnum==0 && jmpcode==0) {
assert(binf!=NULL);
pc_resetasm(outf); /* flush and loop back, for reading */
#if !defined SC_LIGHT
hdrsize=
#endif
assemble(binf,outf); /* assembler file is now input */
} /* if */
pc_resetasm(outf);
assemble(binfname, outf);
}
if (outf!=NULL) {
pc_closeasm(outf,!(sc_asmfile || sc_listing));
outf=NULL;
} /* if */
if (binf!=NULL) {
pc_closebin(binf,errnum!=0);
binf=NULL;
} /* if */
#if !defined SC_LIGHT
#if !defined SC_LIGHT
if (errnum==0 && strlen(errfname)==0) {
#if 0 //bug in compiler -- someone's script caused this function to infrecurs
# if 0 //bug in compiler -- someone's script caused this function to infrecurs
int recursion;
long stacksize=max_stacksize(&glbtab,&recursion);
#endif
# endif
int flag_exceed=0;
if (pc_amxlimit>0) {
long totalsize=hdrsize+code_idx;
long totalsize=code_idx;
if (pc_amxram==0)
totalsize+=(glb_declared+pc_stksize)*sizeof(cell);
if (totalsize>=pc_amxlimit)
@ -498,20 +479,10 @@ cleanup:
if (pc_amxram>0 && (glb_declared+pc_stksize)*sizeof(cell)>=(unsigned long)pc_amxram)
flag_exceed=1;
if ((!norun && (sc_debug & sSYMBOLIC)!=0) || verbosity>=2 || flag_exceed) {
pc_printf("Header size: %8ld bytes\n", (long)hdrsize);
pc_printf("Code size: %8ld bytes\n", (long)code_idx);
pc_printf("Data size: %8ld bytes\n", (long)glb_declared*sizeof(cell));
pc_printf("Stack/heap size: %8ld bytes\n", (long)pc_stksize*sizeof(cell));
#if 0
pc_printf("estimated max. usage");
if (recursion)
pc_printf(": unknown, due to recursion\n");
else if ((pc_memflags & suSLEEP_INSTR)!=0)
pc_printf(": unknown, due to the \"sleep\" instruction\n");
else
pc_printf("=%ld cells (%ld bytes)\n",stacksize,stacksize*sizeof(cell));
#endif
pc_printf("Total requirements:%8ld bytes\n", (long)hdrsize+(long)code_idx+(long)glb_declared*sizeof(cell)+(long)pc_stksize*sizeof(cell));
pc_printf("Total requirements:%8ld bytes\n", (long)code_idx+(long)glb_declared*sizeof(cell)+(long)pc_stksize*sizeof(cell));
} /* if */
if (flag_exceed)
error(166,pc_amxlimit+pc_amxram); /* this causes a jump back to label "cleanup" */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2012-2014 David Anderson
//
// This file is part of SourcePawn.
//
// SourcePawn is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
#include "smx-builder.h"
using namespace ke;
using namespace sp;
SmxBuilder::SmxBuilder()
{
}
bool
SmxBuilder::write(ISmxBuffer *buf)
{
sp_file_hdr_t header;
header.magic = SmxConsts::FILE_MAGIC;
header.version = SmxConsts::SP1_VERSION_1_1;
header.compression = SmxConsts::FILE_COMPRESSION_NONE;
header.disksize = sizeof(header) +
sizeof(sp_file_section_t) * sections_.length();
// Note that |dataoffs| here is just to mimic what it would be in earlier
// versions of Pawn. Its value does not actually matter per the SMX spec,
// aside from having to be >= sizeof(sp_file_hdr_t). Here, we hint that
// only the region after the section list and names should be compressed.
header.dataoffs = header.disksize;
size_t current_string_offset = 0;
for (size_t i = 0; i < sections_.length(); i++) {
Ref<SmxSection> section = sections_[i];
header.disksize += section->length();
current_string_offset += section->name().length() + 1;
}
header.disksize += current_string_offset;
header.dataoffs += current_string_offset;
header.imagesize = header.disksize;
header.sections = sections_.length();
// We put the string table after the sections table.
header.stringtab = sizeof(header) + sizeof(sp_file_section_t) * sections_.length();
if (!buf->write(&header, sizeof(header)))
return false;
size_t current_offset = sizeof(header);
size_t current_data_offset = header.stringtab + current_string_offset;
current_string_offset = 0;
for (size_t i = 0; i < sections_.length(); i++) {
sp_file_section_t s;
s.nameoffs = current_string_offset;
s.dataoffs = current_data_offset;
s.size = sections_[i]->length();
if (!buf->write(&s, sizeof(s)))
return false;
current_offset += sizeof(s);
current_data_offset += s.size;
current_string_offset += sections_[i]->name().length() + 1;
}
assert(buf->pos() == current_offset);
assert(current_offset == header.stringtab);
for (size_t i = 0; i < sections_.length(); i++) {
const AString &name = sections_[i]->name();
if (!buf->write(name.chars(), name.length() + 1))
return false;
}
current_offset += current_string_offset;
assert(buf->pos() == current_offset);
for (size_t i = 0; i < sections_.length(); i++) {
if (!sections_[i]->write(buf))
return false;
current_offset += sections_[i]->length();
}
assert(buf->pos() == current_offset);
assert(current_offset == header.disksize);
return true;
}
bool
SmxNameTable::write(ISmxBuffer *buf)
{
for (size_t i = 0; i < names_.length(); i++) {
Atom *str = names_[i];
if (!buf->write(str->chars(), str->length() + 1))
return false;
}
return true;
}

View File

@ -0,0 +1,180 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2012-2014 AlliedModders LLC, David Anderson
//
// This file is part of SourcePawn.
//
// SourcePawn is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
#ifndef _include_spcomp2_smx_builder_h_
#define _include_spcomp2_smx_builder_h_
#include <am-string.h>
#include <am-vector.h>
#include <am-hashmap.h>
#include <am-refcounting.h>
#include <smx/smx-headers.h>
#include "string-pool.h"
namespace ke {
class ISmxBuffer
{
public:
virtual bool write(const void *bytes, size_t len) = 0;
virtual size_t pos() const = 0;
};
class SmxSection : public Refcounted<SmxSection>
{
public:
SmxSection(const char *name)
: name_(name)
{
}
virtual bool write(ISmxBuffer *buf) = 0;
virtual size_t length() const = 0;
const AString &name() const {
return name_;
}
private:
AString name_;
};
template <typename T>
class SmxBlobSection : public SmxSection
{
public:
SmxBlobSection(const char *name)
: SmxSection(name)
{
}
T &header() {
return t_;
}
void setBlob(uint8_t *blob, size_t len) {
extra_ = blob;
extra_len_ = len;
}
bool write(ISmxBuffer *buf) KE_OVERRIDE {
if (!buf->write(&t_, sizeof(t_)))
return false;
return buf->write(extra_, extra_len_);
}
size_t length() const KE_OVERRIDE {
return sizeof(t_) + extra_len_;
}
private:
T t_;
uint8_t *extra_;
size_t extra_len_;
};
template <typename T>
class SmxListSection : public SmxSection
{
public:
SmxListSection(const char *name)
: SmxSection(name)
{
}
void append(const T &t) {
list_.append(t);
}
T &add() {
list_.append(T());
return list_.back();
}
bool write(ISmxBuffer *buf) KE_OVERRIDE {
return buf->write(list_.buffer(), list_.length() * sizeof(T));
}
size_t length() const KE_OVERRIDE {
return list_.length() * sizeof(T);
}
private:
Vector<T> list_;
};
class SmxNameTable : public SmxSection
{
public:
SmxNameTable(const char *name)
: SmxSection(".names"),
buffer_size_(0)
{
name_table_.init(64);
}
uint32_t add(StringPool &pool, const char *str) {
return add(pool.add(str));
}
uint32_t add(Atom *str) {
NameTable::Insert i = name_table_.findForAdd(str);
if (i.found())
return i->value;
assert(IsUint32AddSafe(buffer_size_, str->length() + 1));
uint32_t index = buffer_size_;
name_table_.add(i, str, index);
names_.append(str);
buffer_size_ += str->length() + 1;
return index;
}
bool write(ISmxBuffer *buf) KE_OVERRIDE;
size_t length() const KE_OVERRIDE {
return buffer_size_;
}
private:
struct HashPolicy {
static uint32_t hash(Atom *str) {
return HashPointer(str);
}
static bool matches(Atom *a, Atom *b) {
return a == b;
}
};
typedef HashMap<Atom *, size_t, HashPolicy> NameTable;
NameTable name_table_;
Vector<Atom *> names_;
uint32_t buffer_size_;
};
class SmxBuilder
{
public:
SmxBuilder();
bool write(ISmxBuffer *buf);
void add(const Ref<SmxSection> &section) {
sections_.append(section);
}
private:
Vector<Ref<SmxSection>> sections_;
};
} // namespace ke
#endif // _include_spcomp2_smx_builder_h_

View File

@ -1,213 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sp_file.h"
#include "memfile.h"
void *mf_open(const char *name);
void mf_close(void *handle);
size_t mf_write(const void *buf, size_t size, size_t count, void *handle);
size_t mf_read(void *buf, size_t size, size_t count, void *handle);
size_t mf_getpos(void *handle);
int mf_setpos(void *handle, size_t pos);
sp_writefuncs_t cstd_funcs =
{
mf_open,
mf_close,
mf_write,
mf_read,
mf_getpos,
mf_setpos
};
sp_file_t *spfw_create(const char *name, sp_writefuncs_t *optfuncs)
{
sp_file_t file;
sp_file_t *pFile;
if (!optfuncs)
optfuncs = &cstd_funcs;
file.handle = optfuncs->fnOpen(name);
if (!file.handle)
return NULL;
pFile = (sp_file_t *)malloc(sizeof(sp_file_t));
pFile->handle = file.handle;
memcpy(&pFile->funcs, optfuncs, sizeof(sp_writefuncs_t));
pFile->curoffs = 0;
pFile->header.magic = SPFILE_MAGIC;
pFile->header.sections = 0;
pFile->header.stringtab = 0;
pFile->header.version = SPFILE_VERSION;
pFile->header.imagesize = 0;
pFile->header.disksize = 0;
pFile->header.compression = SPFILE_COMPRESSION_NONE;
pFile->header.dataoffs = 0;
pFile->lastsection = 0;
pFile->offsets = NULL;
pFile->sections = NULL;
pFile->state = -1;
pFile->nametab = NULL;
pFile->nametab_idx = 0;
return pFile;
}
void spfw_destroy(sp_file_t *spf)
{
free(spf->sections);
free(spf->nametab);
free(spf->offsets);
spf->funcs.fnClose(spf->handle);
free(spf);
}
uint8_t spfw_add_section(sp_file_t *spf, const char *name)
{
size_t namelen;
uint8_t s;
if (spf->state != -1)
return 0;
namelen = strlen(name) + 1;
if (spf->header.sections == 0)
{
/** allocate for first section */
spf->sections = (sp_file_section_t *)malloc(sizeof(sp_file_section_t));
spf->offsets = (size_t *)malloc(sizeof(size_t));
spf->nametab = (char *)malloc(namelen);
} else {
uint16_t num = spf->header.sections + 1;
spf->sections = (sp_file_section_t *)realloc(spf->sections, sizeof(sp_file_section_t) * num);
spf->offsets = (size_t *)realloc(spf->offsets, sizeof(size_t) * num);
spf->nametab = (char *)realloc(spf->nametab, spf->nametab_idx + namelen);
}
s = spf->header.sections;
spf->sections[s].nameoffs = spf->nametab_idx;
/**
* "fix" offset will be the second uint2 slot, which is after the previous sections after the header.
*/
spf->offsets[s] = sizeof(spf->header) + (sizeof(sp_file_section_t) * spf->header.sections) + sizeof(uint32_t);
strcpy(&spf->nametab[spf->nametab_idx], name);
spf->nametab_idx += namelen;
return ++spf->header.sections;
}
int spfw_finalize_header(sp_file_t *spf)
{
uint32_t size;
if (spf->state != -1)
return -1;
size = sizeof(sp_file_section_t) * spf->header.sections;
spf->header.stringtab = sizeof(spf->header) + size;
spf->header.dataoffs = spf->header.stringtab + spf->nametab_idx;
if (spf->funcs.fnWrite(&spf->header, sizeof(spf->header), 1, spf->handle) != 1)
return -1;
if (spf->funcs.fnWrite(spf->sections, sizeof(sp_file_section_t), spf->header.sections, spf->handle) !=
spf->header.sections)
return -1;
if (spf->funcs.fnWrite(spf->nametab, sizeof(char), spf->nametab_idx, spf->handle) != spf->nametab_idx)
return -1;
spf->curoffs = spf->funcs.fnGetPos(spf->handle);
spf->lastsection = spf->curoffs;
spf->state++;
return 0;
}
int spfw_next_section(sp_file_t *spf)
{
uint8_t s;
uint32_t rest[2];
if (spf->state < 0 || spf->state > spf->header.sections)
return -1;
if (spf->state == (int)spf->header.sections)
return 0;
s = (uint8_t)spf->state;
spf->curoffs = spf->funcs.fnGetPos(spf->handle);
spf->funcs.fnSetPos(spf->handle, spf->offsets[s]);
rest[0] = spf->lastsection;
rest[1] = spf->curoffs - spf->lastsection;
if (spf->funcs.fnWrite(rest, sizeof(uint32_t), 2, spf->handle) != 2)
return -1;
spf->funcs.fnSetPos(spf->handle, spf->curoffs);
spf->lastsection = spf->curoffs;
spf->state++;
return 1;
}
int spfw_finalize_all(sp_file_t *spf)
{
uint8_t offs;
if (spf->state < spf->header.sections)
return -1;
offs = offsetof(sp_file_hdr_t, imagesize);
spf->header.disksize = spf->funcs.fnGetPos(spf->handle);
spf->header.imagesize = spf->funcs.fnGetPos(spf->handle);
spf->funcs.fnSetPos(spf->handle, offs);
spf->funcs.fnWrite(&spf->header.imagesize, sizeof(uint32_t), 1, spf->handle);
spf->funcs.fnSetPos(spf->handle, spf->header.imagesize);
return 1;
}
/**
* More memory file operations
*/
void *mf_open(const char *name)
{
return memfile_creat(name, 1024);
}
void mf_close(void *handle)
{
memfile_destroy((memfile_t *)handle);
}
size_t mf_write(const void *buf, size_t size, size_t count, void *handle)
{
if (!count)
return 0;
if (memfile_write((memfile_t *)handle, buf, size*count))
return count;
return 0;
}
size_t mf_read(void *buf, size_t size, size_t count, void *handle)
{
return memfile_read((memfile_t *)handle, buf, size*count) / count;
}
size_t mf_getpos(void *handle)
{
return (long)memfile_tell((memfile_t *)handle);
}
int mf_setpos(void *handle, size_t pos)
{
memfile_seek((memfile_t *)handle, (long)pos);
return 1;
}

View File

@ -1,81 +0,0 @@
#ifndef _INCLUDE_SPFILE_H
#define _INCLUDE_SPFILE_H
#include "sp_file_headers.h"
/**
* Used for overwriting writing routines.
*/
typedef struct sp_writefuncs_s
{
void *(*fnOpen)(const char *); /* filename, returns handle */
void (*fnClose)(void *); /* handle */
/* buffer, size, count, handle, returns count written */
size_t (*fnWrite)(const void *, size_t, size_t, void *);
/* buffer, size, count, handle, returns count read */
size_t (*fnRead)(void *, size_t, size_t, void *);
/* returns current position from start */
size_t (*fnGetPos)(void *);
/* sets current position from start, return 0 for success, nonzero for error */
int (*fnSetPos)(void *, size_t);
} sp_writefuncs_t;
typedef struct sp_file_s
{
sp_file_hdr_t header;
sp_file_section_t *sections;
size_t *offsets;
sp_writefuncs_t funcs;
size_t lastsection;
size_t curoffs;
void *handle;
int state;
char *nametab;
size_t nametab_idx;
} sp_file_t;
/**
* Creates a new SourcePawn binary file.
* You may optionally specify alternative writing functions.
*/
sp_file_t *spfw_create(const char *name, sp_writefuncs_t *optfuncs);
/**
* Closes file handle and frees memory.
*/
void spfw_destroy(sp_file_t *spf);
/**
* Adds a section name to the header.
* Only valid BEFORE finalization.
* Returns the number of sections, or 0 on failure.
*/
uint8_t spfw_add_section(sp_file_t *spf, const char *name);
/**
* Finalizes the section header.
* This means no more sections can be added after this call.
* Also, aligns the writer to the first section.
* Returns 0 on success, nonzero on error.
*/
int spfw_finalize_header(sp_file_t *spf);
/**
* Finalizes the current section and advances to the next.
* In order for this to be accurate, the file pointer must
* reside at the end before calling this, because the size
* is calculated by differencing with the last known offset.
* Returns 1 if there are more sections left, 0 otherwise.
* Returns -1 if the file state is wrong.
*/
int spfw_next_section(sp_file_t *spf);
/**
* Finalizes all sections.
* Cannot be called until all sections are used.
* Must be called with the file pointer at the end.
* Also does compression!
*/
int spfw_finalize_all(sp_file_t *spf);
#endif //_INCLUDE_SPFILE_H

View File

@ -1,291 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SPFILE_HEADERS_H
#define _INCLUDE_SPFILE_HEADERS_H
/**
* @file sp_file_headers.h
* @brief Defines the structure present in a SourcePawn compiled binary.
*
* Note: These structures should be 1-byte packed to match the file format.
*/
#include <stddef.h>
#include <stdint.h>
#define SPFILE_MAGIC 0x53504646 /**< Source Pawn File Format (SPFF) */
#define SPFILE_VERSION 0x0102 /**< File format version */
//:TODO: better compiler/nix support
#if defined __GNUC__
#pragma pack(1) /* structures must be packed (byte-aligned) */
#else
#pragma pack(push)
#pragma pack(1) /* structures must be packed (byte-aligned) */
#endif
#define SPFILE_COMPRESSION_NONE 0 /**< No compression in file */
#define SPFILE_COMPRESSION_GZ 1 /**< GZ compression */
/**
* @brief File section header format.
*/
typedef struct sp_file_section_s
{
uint32_t nameoffs; /**< Relative offset into global string table */
uint32_t dataoffs; /**< Offset into the data section of the file */
uint32_t size; /**< Size of the section's entry in the data section */
} sp_file_section_t;
/**
* @brief File header format. If compression is 0, then disksize may be 0
* to mean that only the imagesize is needed.
*/
typedef struct sp_file_hdr_s
{
uint32_t magic; /**< Magic number */
uint16_t version; /**< Version code */
uint8_t compression;/**< Compression algorithm */
uint32_t disksize; /**< Size on disk */
uint32_t imagesize; /**< Size in memory */
uint8_t sections; /**< Number of sections */
uint32_t stringtab; /**< Offset to string table */
uint32_t dataoffs; /**< Offset to file proper (any compression starts here) */
} sp_file_hdr_t;
#define SP_FLAG_DEBUG (1<<0) /**< Debug information is present in the file */
#define SP_CODEVERS_JIT1 9 /**< Code version for JIT1 */
#define SP_CODEVERS_JIT2 10 /**< Code version for JIT2 */
/**
* @brief File-encoded format of the ".code" section.
*/
typedef struct sp_file_code_s
{
uint32_t codesize; /**< Codesize in bytes */
uint8_t cellsize; /**< Cellsize in bytes */
uint8_t codeversion; /**< Version of opcodes supported */
uint16_t flags; /**< Flags */
uint32_t main; /**< Address to "main," if any */
uint32_t code; /**< Relative offset to code */
} sp_file_code_t;
/**
* @brief File-encoded format of the ".data" section.
*/
typedef struct sp_file_data_s
{
uint32_t datasize; /**< Size of data section in memory */
uint32_t memsize; /**< Total mem required (includes data) */
uint32_t data; /**< File offset to data (helper) */
} sp_file_data_t;
/**
* @brief File-encoded format of the ".publics" section.
*/
typedef struct sp_file_publics_s
{
uint32_t address; /**< Address relative to code section */
uint32_t name; /**< Index into nametable */
} sp_file_publics_t;
/**
* @brief File-encoded format of the ".natives" section.
*/
typedef struct sp_file_natives_s
{
uint32_t name; /**< Index into nametable */
} sp_file_natives_t;
/**
* @brief File-encoded format of the ".pubvars" section.
*/
typedef struct sp_file_pubvars_s
{
uint32_t address; /**< Address relative to the DAT section */
uint32_t name; /**< Index into nametable */
} sp_file_pubvars_t;
/**
* @brief File-encoded tag info.
*/
typedef struct sp_file_tag_s
{
uint32_t tag_id; /**< Tag ID from compiler */
uint32_t name; /**< Index into nametable */
} sp_file_tag_t;
/**
* @brief File-encoded debug information table.
*/
typedef struct sp_fdbg_info_s
{
uint32_t num_files; /**< number of files */
uint32_t num_lines; /**< number of lines */
uint32_t num_syms; /**< number of symbols */
uint32_t num_arrays; /**< number of symbols which are arrays */
} sp_fdbg_info_t;
/**
* @brief File-encoded debug file table.
*/
typedef struct sp_fdbg_file_s
{
uint32_t addr; /**< Address into code */
uint32_t name; /**< Offset into debug nametable */
} sp_fdbg_file_t;
/**
* @brief File-encoded debug line table.
*/
typedef struct sp_fdbg_line_s
{
uint32_t addr; /**< Address into code */
uint32_t line; /**< Line number */
} sp_fdbg_line_t;
#define SP_SYM_VARIABLE 1 /**< Cell that has an address and that can be fetched directly (lvalue) */
#define SP_SYM_REFERENCE 2 /**< VARIABLE, but must be dereferenced */
#define SP_SYM_ARRAY 3 /**< Symbol is an array */
#define SP_SYM_REFARRAY 4 /**< An array passed by reference (i.e. a pointer) */
#define SP_SYM_FUNCTION 9 /**< Symbol is a function */
#define SP_SYM_VARARGS 11 /**< Variadic argument start. */
/**
* @brief File-encoded debug symbol information.
*/
typedef struct sp_fdbg_symbol_s
{
int32_t addr; /**< Address rel to DAT or stack frame */
int16_t tagid; /**< Tag id */
uint32_t codestart; /**< Start scope validity in code */
uint32_t codeend; /**< End scope validity in code */
uint8_t ident; /**< Variable type */
uint8_t vclass; /**< Scope class (local vs global) */
uint16_t dimcount; /**< Dimension count (for arrays) */
uint32_t name; /**< Offset into debug nametable */
} sp_fdbg_symbol_t;
/**
* @brief File-encoded debug symbol array dimension info.
*/
typedef struct sp_fdbg_arraydim_s
{
int16_t tagid; /**< Tag id */
uint32_t size; /**< Size of dimension */
} sp_fdbg_arraydim_t;
/** Typedef for .names table */
typedef char * sp_file_nametab_t;
/**
* @brief File encoding for the dbg.natives table.
*
* This header is followed by variable length entries of sp_fdbg_native.
*/
typedef struct sp_fdbg_ntvtab_s
{
uint32_t num_entries; /**< Number of entries. */
} sp_fdbg_ntvtab_t;
#define SP_NTVDBG_VARARGS (1<<0) /**< Formal args are followed by '...' */
/**
* @brief File encoding of native debug info.
*
* Each entry is followed by an sp_fdbg_ntvarg_t for each narg.
*/
typedef struct sp_fdbg_native_s
{
uint32_t index; /**< Native index in the plugin. */
uint32_t name; /**< Offset into debug nametable. */
int16_t tagid; /**< Return tag. */
uint16_t nargs; /**< Number of formal arguments. */
} sp_fdbg_native_t;
/**
* @brief File encoding of native arguments.
*
* Each entry is followed by an sp_fdbg_arraydim_t for each dimcount.
*/
typedef struct fp_fdbg_ntvarg_s
{
uint8_t ident; /**< Variable type */
int16_t tagid; /**< Tag id */
uint16_t dimcount; /**< Dimension count (for arrays) */
uint32_t name; /**< Offset into debug nametable */
} sp_fdbg_ntvarg_t;
#if defined __GNUC__
#pragma pack() /* reset default packing */
#else
#pragma pack(pop) /* reset previous packing */
#endif
/**
* Okay, my mistake here. I apologize. I changed the packing by accident and there is no
* version bump aside from the presence of the native debug table. Cat's out of the bag
* for SourceMod and we have no choice but to shim compat for the old version. For people
* parsing plugins on their own, use the presence of the native debug table to decide this.
* If there are no natives (really, there is a very very low chance of this), heuristics
* might be necessary. I've bumped the version to 0x0102 but there may have been plugins
* in the 0x0101 window with no natives.
*/
/**
* @brief Unpacked file-encoded debug symbol array dimension info.
*/
typedef struct sp_u_fdbg_arraydim_s
{
int16_t tagid; /**< Tag id */
uint32_t size; /**< Size of dimension */
} sp_u_fdbg_arraydim_t;
/**
* @brief Unpacked file-encoded debug symbol information.
*/
typedef struct sp_u_fdbg_symbol_s
{
int32_t addr; /**< Address rel to DAT or stack frame */
int16_t tagid; /**< Tag id */
uint32_t codestart; /**< Start scope validity in code */
uint32_t codeend; /**< End scope validity in code */
uint8_t ident; /**< Variable type */
uint8_t vclass; /**< Scope class (local vs global) */
uint16_t dimcount; /**< Dimension count (for arrays) */
uint32_t name; /**< Offset into debug nametable */
} sp_u_fdbg_symbol_t;
#endif //_INCLUDE_SPFILE_HEADERS_H

View File

@ -2,7 +2,6 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sp_file_headers.h"
#include "sc.h"
#include "sp_symhash.h"
#include <am-hashtable.h>

View File

@ -0,0 +1,139 @@
/* vim: set ts=2 sw=2 tw=99 et:
*
* Copyright (C) 2012-2014 AlliedModders LLC, David Anderson
*
* This file is part of SourcePawn.
*
* SourcePawn is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SourcePawn. If not, see http://www.gnu.org/licenses/.
*/
#ifndef _include_jitcraft_string_pool_h_
#define _include_jitcraft_string_pool_h_
#include <am-hashtable.h>
#include <am-string.h>
#include <string.h>
namespace ke {
// Wrapper around AString, since we might want to remove charfs() in a GC-safe
// implementation.
class Atom
{
friend class StringPool;
private:
Atom(const char *str, size_t len)
: str_(str, len)
{
}
public:
size_t length() const {
return str_.length();
}
const char *chars() const {
return str_.chars();
}
private:
AString str_;
};
class CharsAndLength
{
public:
CharsAndLength()
: str_(nullptr),
length_(0)
{
}
CharsAndLength(const char *str, size_t length)
: str_(str),
length_(length)
{
}
const char *str() const {
return str_;
}
size_t length() const {
return length_;
}
private:
const char *str_;
size_t length_;
};
class StringPool
{
public:
StringPool()
: table_(SystemAllocatorPolicy())
{
init();
}
~StringPool()
{
if (!table_.elements())
return;
for (Table::iterator i(&table_); !i.empty(); i.next())
delete *i;
}
bool init() {
return table_.init(256);
}
Atom *add(const char *str, size_t length) {
CharsAndLength chars(str, length);
Table::Insert p = table_.findForAdd(chars);
if (!p.found() && !table_.add(p, new Atom(str, length)))
return nullptr;
return *p;
}
Atom *add(const char *str) {
return add(str, strlen(str));
}
private:
struct Policy {
typedef Atom *Payload;
static uint32_t hash(const char *key) {
return HashCharSequence(key, strlen(key));
}
static uint32_t hash(const CharsAndLength &key) {
return HashCharSequence(key.str(), key.length());
}
static bool matches(const CharsAndLength &key, const Payload &e) {
if (key.length() != e->length())
return false;
return strcmp(key.str(), e->chars()) == 0;
}
};
typedef HashTable<Policy> Table;
private:
Table table_;
};
} // namespace ke
#endif // _include_jitcraft_string_pool_h_

View File

@ -39,9 +39,8 @@ struct SmxConsts
static const uint32_t FILE_MAGIC = 0x53504646;
// File format verison number.
// 0x0101 - Initial version used by spcomp1 and SourceMod 1.0.
// 0x0102 - Used by spcomp1 and SourceMod 1.1+.
// 0x0103 - Used by SourceMod 1.7+.
// 0x0101 - SourcePawn 1.0; initial version used by SourceMod 1.0.
// 0x0102 - SourcePawn 1.1; used by SourceMod 1.1+.
// 0x0200 - Used by spcomp2.
//
// The major version bits (8-15) indicate a product number. Consumers should
@ -49,8 +48,10 @@ struct SmxConsts
//
// The minor version bits (0-7) indicate a compatibility revision. Any minor
// version higher than the current version should be rejected.
static const uint16_t SP1_VERSION_MIN = 0x0101;
static const uint16_t SP1_VERSION_MAX = 0x0103;
static const uint16_t SP1_VERSION_1_0 = 0x0101;
static const uint16_t SP1_VERSION_1_1 = 0x0102;
static const uint16_t SP1_VERSION_MIN = SP1_VERSION_1_0;
static const uint16_t SP1_VERSION_MAX = SP1_VERSION_1_1;
static const uint16_t SP2_VERSION_MIN = 0x0200;
static const uint16_t SP2_VERSION_MAX = 0x0200;
@ -94,18 +95,28 @@ typedef struct sp_file_hdr_s
uint32_t magic;
uint16_t version;
// Compression algorithm. If the file is not compressed, then imagesize and
// disksize are the same value, and dataoffs is 0.
// disksize, imagesize, and dataoffs (at the end) describe a region of the
// file that may be compressed. The region must occur after the initial
// sp_file_hdr_t header. For SourceMod compatibility, the meanings are as
// follows.
//
// The start of the compressed region is indicated by dataoffs. The length
// of the compressed region is (disksize - dataoffs). The amount of memory
// required to hold the decompressed bytes is (imagesize - dataoffs). The
// compressed region should be expanded in-place. That is, bytes before
// "dataoffs" should be retained, and the decompressed region should be
// appended.
// Without compression:
// imagesize is the amount of bytes that must be read into memory to parse
// the SMX container, starting from the first byte of the file.
// disksize is undefined.
// dataoffs is undefined.
//
// |imagesize| is the amount of memory required to hold the entire container
// in memory.
// With compression:
// dataoffs is an offset to the start of the compression region.
// disksize is the length of the compressed region, in bytes, plus dataoffs.
// imagesize is the size of the entire SMX container after decompression.
//
// This means that at least |imagesize-dataoffs| must be allocated to
// decompress, and the compressed region's length is |datasize-dataoffs|.
//
// The compressed region should always be expanded "in-place". That is, to
// parse the container, the compressed bytes should be replaced with
// decompressed bytes.
//
// Note: This scheme may seem odd. It's a combination of historical debt and
// previously unspecified behavior. The original .amx file format contained

View File

@ -53,7 +53,7 @@ LINK = -m32 -lm -lpthread -lrt
INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \
-I$(SMSDK)/public/sourcepawn -I$(MMSOURCE17)/core/sourcehook -I$(SMSDK)/knight/shared -Ix86 \
-I$(SMSDK)/public/amtl
-I$(SMSDK)/public/amtl -I$(SMSDK)/sourcepawn/include
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \