Merge pull request #141 from alliedmodders/calli-5

Rewrite the assembly pipeline.
This commit is contained in:
David Anderson 2014-09-07 15:04:00 -07:00
commit 06f52aa7ce
20 changed files with 1214 additions and 2176 deletions

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,103 @@
// 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"
// Interface for SmxBuilder to blit bytes.
class ISmxBuffer
{
public:
virtual bool write(const void *bytes, size_t len) = 0;
virtual size_t pos() const = 0;
};
// An in-memory buffer for SmxBuilder.
class MemoryBuffer : public 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;
return pc_compile(argc,argv);
}
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;
}
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

@ -579,13 +579,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);
@ -768,7 +761,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

@ -201,16 +201,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);
@ -316,14 +311,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)
@ -464,23 +451,17 @@ 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 (errnum==0 && strlen(errfname)==0) {
@ -490,7 +471,7 @@ cleanup:
# 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)
@ -499,20 +480,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" */
@ -2077,8 +2048,6 @@ static void declglb(declinfo_t *decl,int fpublic,int fstatic,int fstock)
static void declloc(int tokid)
{
symbol *sym;
cell val;
char *str;
value lval = {0};
int cur_lit=0;
int staging_start;
@ -2828,7 +2797,7 @@ static void decl_const(int vclass)
char constname[sNAMEMAX+1];
cell val;
token_t tok;
int tag,exprtag;
int exprtag;
int symbolline;
symbol *sym;
@ -2906,7 +2875,6 @@ static void declstruct(void)
char *str;
int tok;
pstruct_t *pstruct;
int size;
/* get the explicit tag (required!) */
tok = lex(&val,&str);
@ -3790,7 +3758,6 @@ methodmap_method_t *parse_method(methodmap_t *map)
typeinfo_t type;
memset(&type, 0, sizeof(type));
token_t tok;
if (matchtoken('~')) {
// We got something like "public ~Blah = X"
is_bind = TRUE;
@ -5076,9 +5043,8 @@ static cell fix_char_size(declinfo_t *decl)
static symbol *funcstub(int tokid, declinfo_t *decl, const int *thistag)
{
int tok;
char *str;
cell val,size;
cell val;
symbol *sym;
int fnative = (tokid == tNATIVE || tokid == tMETHODMAP);
int fpublic = (tokid == tPUBLIC);
@ -5182,10 +5148,9 @@ static symbol *funcstub(int tokid, declinfo_t *decl, const int *thistag)
static int newfunc(declinfo_t *decl, const int *thistag, int fpublic, int fstatic, int stock, symbol **symp)
{
symbol *sym;
int argcnt,tok,funcline;
int argcnt,funcline;
int opererror;
char *str;
cell val,cidx,glbdecl;
cell cidx,glbdecl;
short filenum;
assert(litidx==0); /* literal queue should be empty */
@ -5456,7 +5421,7 @@ static int argcompare(arginfo *a1,arginfo *a2)
static int declargs(symbol *sym, int chkshadow, const int *thistag)
{
char *ptr;
int argcnt,oldargcnt,tok;
int argcnt,oldargcnt;
arginfo arg, *arglist;
char name[sNAMEMAX+1];
int fpublic;

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,214 @@
// 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"
#include "memory-buffer.h"
namespace ke {
// An SmxSection is a named blob of data.
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_;
};
// An SmxBlobSection is a section that has some kind of header structure
// (specified as a template parameter), and then an arbitrary run of bytes
// immediately after.
template <typename T>
class SmxBlobSection : public SmxSection
{
public:
SmxBlobSection(const char *name)
: SmxSection(name),
extra_(nullptr),
extra_len_(0)
{
memset(&t_, 0, sizeof(t_));
}
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;
if (!extra_len_)
return true;
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_;
};
// An SmxBlobSection without headers.
template <>
class SmxBlobSection<void> : public SmxSection
{
public:
SmxBlobSection(const char *name)
: SmxSection(name)
{
}
void add(void *bytes, size_t len) {
buffer_.write(bytes, len);
}
bool write(ISmxBuffer *buf) KE_OVERRIDE {
return buf->write(buffer_.bytes(), buffer_.size());
}
size_t length() const KE_OVERRIDE {
return buffer_.size();
}
private:
MemoryBuffer buffer_;
};
// An SmxListSection is a section that is a simple table of uniformly-sized
// structures. It has no header of its own.
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 count() * sizeof(T);
}
size_t count() const {
return list_.length();
}
private:
Vector<T> list_;
};
// A name table is a blob of zero-terminated strings. Strings are entered
// into the table as atoms, so duplicate stings are not emitted.
class SmxNameTable : public SmxSection
{
public:
SmxNameTable(const char *name)
: SmxSection(name),
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,146 @@
/* 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_
// string-pool is a collection of helpers to atomize/internalize strings. The
// StringPool class provides Atom objects which can be used for efficiently
// handling string sets or dictionaries.
#include <am-hashtable.h>
#include <am-string.h>
#include <string.h>
namespace ke {
// An Atom is a string that has a unique instance. That is, any Atom("a") is
// guaranteed to be pointer-equivalent to another Atom("a"), as long as they
// originated from the same StringPool.
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_;
};
// Helper class to use as a key for hash table lookups.
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_;
};
// Atom dictionary.
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,11 @@ 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_1_7 = 0x0107;
static const uint16_t SP1_VERSION_MIN = SP1_VERSION_1_0;
static const uint16_t SP1_VERSION_MAX = SP1_VERSION_1_7;
static const uint16_t SP2_VERSION_MIN = 0x0200;
static const uint16_t SP2_VERSION_MAX = 0x0200;
@ -58,11 +60,12 @@ struct SmxConsts
static const uint8_t FILE_COMPRESSION_NONE = 0;
static const uint8_t FILE_COMPRESSION_GZ = 1;
// SourcePawn 1.0.
static const uint8_t CODE_VERSION_JIT1 = 9;
// SourcePawn 1.1.
static const uint8_t CODE_VERSION_JIT2 = 10;
// SourcePawn 1.
static const uint8_t CODE_VERSION_JIT_1_0 = 9;
static const uint8_t CODE_VERSION_JIT_1_1 = 10;
static const uint8_t CODE_VERSION_JIT_1_7 = 11;
static const uint8_t CODE_VERSION_SP1_MIN = CODE_VERSION_JIT_1_0;
static const uint8_t CODE_VERSION_SP1_MAX = CODE_VERSION_JIT_1_1;
// For SP1 consumers, the container version may not be checked, but usually
// the code version is. This constant allows newer containers to be rejected
@ -94,18 +97,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

@ -161,6 +161,10 @@ typedef struct sp_fdbg_ntvarg_s
uint32_t name; /**< Offset into debug nametable */
} sp_fdbg_ntvarg_t;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// DO NOT DEFINE NEW STRUCTURES BELOW.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#if defined __GNUC__
# pragma pack() /* reset default packing */
#else

View File

@ -172,9 +172,9 @@ int BaseRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base)
if (!(m_plugin.pcode) && !strcmp(nameptr, ".code")) {
sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
if (cod->codeversion < SmxConsts::CODE_VERSION_JIT1)
if (cod->codeversion < SmxConsts::CODE_VERSION_SP1_MIN)
return SP_ERROR_CODE_TOO_OLD;
if (cod->codeversion > SmxConsts::CODE_VERSION_JIT2)
if (cod->codeversion > SmxConsts::CODE_VERSION_SP1_MAX)
return SP_ERROR_CODE_TOO_NEW;
m_plugin.pcode = base + secptr->dataoffs + cod->code;

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 \

View File

@ -147,7 +147,7 @@ void SourcePawnEngine2::DestroyFakeNative(SPVM_NATIVE_FUNC func)
const char *SourcePawnEngine2::GetEngineName()
{
return "SourcePawn 1.3, jit-x86";
return "SourcePawn 1.7, jit-x86";
}
const char *SourcePawnEngine2::GetVersionString()