From 76ee08eb14b9ef7db14a0dc422677987f7c663d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sun, 5 Nov 2023 13:59:58 -0800 Subject: [PATCH 1/8] separate dynamic and static functions based on reference module --- w2c2/c.c | 207 ++++++++++++++++++++++++++--------------------- w2c2/c.h | 8 +- w2c2/function.h | 24 +++++- w2c2/main.c | 149 ++++++++++++++++++++++++++++++++-- w2c2/reader.c | 4 + w2c2/sha1.c | 188 ++++++++++++++++++++++++++++++++++++++++++ w2c2/sha1.h | 21 +++++ w2c2/sha1_test.c | 47 +++++++++++ w2c2/sha1_test.h | 7 ++ w2c2/test.c | 2 + w2c2/w2c2_base.h | 2 +- 11 files changed, 559 insertions(+), 100 deletions(-) create mode 100644 w2c2/sha1.c create mode 100644 w2c2/sha1.h create mode 100644 w2c2/sha1_test.c create mode 100644 w2c2/sha1_test.h diff --git a/w2c2/c.c b/w2c2/c.c index c3fbcff0..4aa4ee09 100644 --- a/w2c2/c.c +++ b/w2c2/c.c @@ -3470,8 +3470,9 @@ wasmCWriteFunctionImplementations( const WasmModule* module, const char *moduleName, WasmDebugLines* debugLines, - U32 startIndex, - U32 endIndex, + U32 startIDIndex, + U32 endIDIndex, + WasmFunctionIDs functionIDs, bool pretty, bool debug, bool multipleModules @@ -3482,8 +3483,10 @@ wasmCWriteFunctionImplementations( WasmTypeStack stackDeclarations = wasmEmptyTypeStack; WasmLabelStack labelStack = wasmEmptyLabelStack; - U32 functionIndex = startIndex; - for (; functionIndex < endIndex; functionIndex++) { + U32 functionIDIndex = startIDIndex; + for (; functionIDIndex < endIDIndex; functionIDIndex++) { + WasmFunctionID functionID = functionIDs.functionIDs[functionIDIndex]; + U32 functionIndex = functionID.functionIndex; const WasmFunction function = module->functions.functions[functionIndex]; wasmTypeStackClear(&typeStack); @@ -3830,8 +3833,7 @@ wasmCWriteInitImports( FILE* file, const WasmModule* module, const char* moduleName, - bool pretty, - bool multipleModules + bool pretty ) { fprintf( file, @@ -4702,7 +4704,7 @@ wasmCWriteInits( MUST (wasmCWriteInitMemories(file, module, moduleName, dataSegmentMode, pretty)) MUST (wasmCWriteInitTables(file, module, moduleName, pretty, multipleModules)) MUST (wasmCWriteInitGlobals(file, module, moduleName, pretty)) - MUST (wasmCWriteInitImports(file, module, moduleName, pretty, multipleModules)) + MUST (wasmCWriteInitImports(file, module, moduleName, pretty)) wasmCWriteExports(file, module, moduleName, true, pretty, multipleModules); @@ -4722,65 +4724,61 @@ wasmCWriteImplementationFile( WasmDebugLines* debugLines, U32 fileIndex, U32 functionsPerFile, - FILE* file, - U32 startFunctionIndex, + U32 startFunctionIDIndex, + WasmFunctionIDs functionIDs, bool pretty, bool debug, bool multipleModules ) { + FILE* file = NULL; char filename[13]; - U32 functionCount = module->functions.count; - bool separate = file == NULL; + U32 functionCount = (U32)functionIDs.length; - U32 endFunctionIndex = startFunctionIndex + functionsPerFile; - if (endFunctionIndex > functionCount) { - endFunctionIndex = functionCount; + U32 endFunctionIDIndex = startFunctionIDIndex + (U32)functionsPerFile; + if (endFunctionIDIndex > functionCount) { + endFunctionIDIndex = functionCount; } /* Do not create empty files */ - if (startFunctionIndex > endFunctionIndex) { + if (startFunctionIDIndex > endFunctionIDIndex) { return true; } - if (separate) { - sprintf(filename, "%010u.c", fileIndex); - file = fopen(filename, "w"); - if (file == NULL) { - fprintf( - stderr, - "w2c2: failed to create implementation file %s: %s\n", - filename, - strerror(errno) - ); - return false; - } - wasmCWriteIncludes(file, headerName); + sprintf(filename, "%010u.c", fileIndex); + file = fopen(filename, "w"); + if (file == NULL) { + fprintf( + stderr, + "w2c2: failed to create implementation file %s: %s\n", + filename, + strerror(errno) + ); + return false; } - { - MUST (wasmCWriteFunctionImplementations( - file, - module, - moduleName, - debugLines, - startFunctionIndex, - endFunctionIndex, - pretty, - debug, - multipleModules - )) - } + wasmCWriteIncludes(file, headerName); - if (separate) { - if (fclose(file) != 0) { - fprintf( - stderr, - "w2c2: failed to close implementation file: %s: %s\n", - filename, - strerror(errno) - ); - return false; - } + MUST (wasmCWriteFunctionImplementations( + file, + module, + moduleName, + debugLines, + startFunctionIDIndex, + endFunctionIDIndex, + functionIDs, + pretty, + debug, + multipleModules + )) + + if (fclose(file) != 0) { + fprintf( + stderr, + "w2c2: failed to close implementation file: %s: %s\n", + filename, + strerror(errno) + ); + return false; } return true; @@ -4794,7 +4792,8 @@ typedef struct WasmCImplementationWriterTask { const WasmModule* module; const char* moduleName; const char* headerName; - U32 startFunctionIndex; + U32 startFunctionIDIndex; + WasmFunctionIDs functionIDs; bool pretty; bool debug; bool multipleModules; @@ -4864,7 +4863,8 @@ wasmCImplementationWriterThread( const char* headerName = task->headerName; U32 fileIndex = task->fileIndex; U32 functionsPerFile = task->functionsPerFile; - U32 startFunctionIndex = task->startFunctionIndex; + U32 startFunctionIDIndex = task->startFunctionIDIndex; + WasmFunctionIDs functionIDs = task->functionIDs; bool pretty = task->pretty; bool debug = task->debug; bool multipleModules = task->multipleModules; @@ -4881,18 +4881,19 @@ wasmCImplementationWriterThread( NULL, fileIndex, functionsPerFile, - NULL, - startFunctionIndex, + startFunctionIDIndex, + functionIDs, pretty, debug, multipleModules ); if (!result) { + WasmFunctionID startFunctionID = functionIDs.functionIDs[startFunctionIDIndex]; fprintf( stderr, - "w2c2: failed to write implementation file %d, start func %d\n", + "w2c2: failed to write implementation file %d. start function index: %d\n", fileIndex, - startFunctionIndex + startFunctionID.functionIndex ); exit(1); } @@ -4912,34 +4913,24 @@ wasmCWriteModuleImplementationFiles( const WasmModule* module, const char* moduleName, const char* headerName, - FILE* mainFile, + WasmFunctionIDs functionIDs, + U32* fileIndex, WasmCWriteModuleOptions options ) { WasmDebugLines debugLines = module->debugLines; - U32 fileIndex = 0; - U32 functionCount = module->functions.count; + size_t functionCount = functionIDs.length; U32 functionsPerFile = options.functionsPerFile; - U32 fileCount = 0; - if (functionCount > 0) { - fileCount = 1 + (functionCount - 1) / functionsPerFile; + size_t fileCount = 0; + if (functionCount == 0) { + return true; } - - MUST (wasmCWriteImplementationFile( - module, - moduleName, - headerName, - &debugLines, - fileIndex++, - functionsPerFile, - mainFile, - 0, - options.pretty, - options.debug, - options.multipleModules - )) + fileCount = 1 + (functionCount - 1) / functionsPerFile; { + size_t totalFileCount = *fileIndex + fileCount; + U32 startFunctionIDIndex = 0; + #if HAS_PTHREAD U32 threadCount = options.threadCount; pthread_t* threads = calloc(threadCount * sizeof(pthread_t), 1); @@ -4974,8 +4965,11 @@ wasmCWriteModuleImplementationFiles( } #endif /* HAS_PTHREAD */ - for (; fileIndex < fileCount; fileIndex++) { - U32 startFunctionIndex = fileIndex * functionsPerFile; + for (; + *fileIndex < totalFileCount; + (*fileIndex)++, + startFunctionIDIndex += functionsPerFile + ) { #if HAS_PTHREAD pthread_mutex_lock(&writer.mutex); @@ -4986,8 +4980,9 @@ wasmCWriteModuleImplementationFiles( ); } - task.fileIndex = fileIndex; - task.startFunctionIndex = startFunctionIndex; + task.fileIndex = *fileIndex; + task.startFunctionIDIndex = startFunctionIDIndex; + task.functionIDs = functionIDs; writer.task = &task; @@ -5000,10 +4995,10 @@ wasmCWriteModuleImplementationFiles( moduleName, headerName, &debugLines, - fileIndex, + *fileIndex, functionsPerFile, - NULL, - startFunctionIndex, + startFunctionIDIndex, + functionIDs, options.pretty, options.debug, options.multipleModules @@ -5050,8 +5045,12 @@ wasmCWriteModuleImplementation( const char* moduleName, const char* filename, const char* headerName, + WasmFunctionIDs staticFunctionIDs, + WasmFunctionIDs dynamicFunctionIDs, WasmCWriteModuleOptions options ) { + U32 fileIndex = 0; + /* Create file */ FILE *file = NULL; @@ -5074,7 +5073,17 @@ wasmCWriteModuleImplementation( module, moduleName, headerName, - file, + staticFunctionIDs, + &fileIndex, + options + )) + + MUST (wasmCWriteModuleImplementationFiles( + module, + moduleName, + headerName, + dynamicFunctionIDs, + &fileIndex, options )) @@ -5107,9 +5116,11 @@ wasmCWriteModuleImplementation( bool WARN_UNUSED_RESULT wasmCWriteModule( - const WasmModule* module, - const char* moduleName, - WasmCWriteModuleOptions options + const WasmModule *module, + const char *moduleName, + WasmCWriteModuleOptions options, + WasmFunctionIDs staticFunctionIDs, + WasmFunctionIDs dynamicFunctionIDs ) { char outputDir[PATH_MAX]; char outputName[PATH_MAX]; @@ -5139,8 +5150,24 @@ wasmCWriteModule( return false; } - MUST (wasmCWriteModuleHeader(module, moduleName, headerName, options.pretty, options.debug, options.multipleModules)) - MUST (wasmCWriteModuleImplementation(module, moduleName, outputName, headerName, options)) + MUST (wasmCWriteModuleHeader( + module, + moduleName, + headerName, + options.pretty, + options.debug, + options.multipleModules + )) + + MUST (wasmCWriteModuleImplementation( + module, + moduleName, + outputName, + headerName, + staticFunctionIDs, + dynamicFunctionIDs, + options + )) return true; } diff --git a/w2c2/c.h b/w2c2/c.h index 22f4e3b8..1070a3de 100644 --- a/w2c2/c.h +++ b/w2c2/c.h @@ -21,9 +21,11 @@ static const WasmCWriteModuleOptions emptyWasmCWriteModuleOptions ={ bool WARN_UNUSED_RESULT wasmCWriteModule( - const WasmModule* module, - const char* moduleName, - WasmCWriteModuleOptions options + const WasmModule *module, + const char *moduleName, + WasmCWriteModuleOptions options, + WasmFunctionIDs staticFunctionIDs, + WasmFunctionIDs dynamicFunctionIDs ); #endif /* W2C2_C_H */ diff --git a/w2c2/function.h b/w2c2/function.h index 4a796221..4148b418 100644 --- a/w2c2/function.h +++ b/w2c2/function.h @@ -4,6 +4,8 @@ #include "w2c2_base.h" #include "buffer.h" #include "locals.h" +#include "array.h" +#include "sha1.h" typedef struct WasmFunction { U32 functionTypeIndex; @@ -11,9 +13,29 @@ typedef struct WasmFunction { Buffer code; /* Offset relative to the code section start (function count) */ size_t start; + /* Hash of the locals (as declared in the binary) and the code */ + unsigned char hash[SHA1_DIGEST_LENGTH]; } WasmFunction; static const WasmFunction wasmEmptyFunction = - {0, {NULL, 0}, {NULL, 0}, 0}; + {0, {NULL, 0}, {NULL, 0}, 0, SHA1_DIGEST_EMPTY}; + +typedef struct WasmFunctionID { + /* Hash of the locals (as declared in the binary) and the code */ + unsigned char hash[SHA1_DIGEST_LENGTH]; + U32 functionIndex; +} WasmFunctionID; + +static const WasmFunctionID emptyWasmFunctionID = {SHA1_DIGEST_EMPTY, 0}; + +ARRAY_TYPE( + WasmFunctionIDs, + WasmFunctionID, + wasmFunctionIDs, + functionIDs, + functionID +) + +static const WasmFunctionIDs emptyWasmFunctionIDs = {0, 0, NULL}; #endif /* W2C2_FUNCTION_H */ diff --git a/w2c2/main.c b/w2c2/main.c index ed7f1690..5c5445d7 100644 --- a/w2c2/main.c +++ b/w2c2/main.c @@ -22,9 +22,9 @@ #include "stringbuilder.h" #if HAS_PTHREAD -static char* const optString = "t:f:d:pgmh"; +static char* const optString = "t:f:d:r:pgmh"; #else -static char* const optString = "f:d:pgmh"; +static char* const optString = "f:d:r:pgmh"; #endif /* HAS_PTHREAD */ static @@ -46,7 +46,12 @@ readWasmBinary( wasmModuleRead(wasmModuleReaderResult, &error); if (error != NULL) { - fprintf(stderr, "w2c2: failed to read module: %s\n", wasmModuleReaderErrorMessage(error)); + fprintf( + stderr, + "w2c2: failed to read module %s: %s\n", + path, + wasmModuleReaderErrorMessage(error) + ); return false; } @@ -82,6 +87,88 @@ getPathModuleName( moduleName[j] = '\0'; } +int wasmFunctionIDsCompareHashes(const void* a, const void* b) { + const WasmFunctionID* functionIDA = a; + const WasmFunctionID* functionIDB = b; + return memcmp(functionIDA->hash, functionIDB->hash, SHA1_DIGEST_LENGTH); +} + +WasmFunctionIDs wasmSortedFunctionIDs(WasmFunctions functions) { + WasmFunctionIDs result = emptyWasmFunctionIDs; + + U32 functionIndex = 0; + for (; functionIndex < functions.count; functionIndex++) { + WasmFunction function = functions.functions[functionIndex]; + WasmFunctionID functionID = emptyWasmFunctionID; + memcpy(functionID.hash, function.hash, SHA1_DIGEST_LENGTH); + functionID.functionIndex = functionIndex; + if (!wasmFunctionIDsAppend(&result, functionID)) { + exit(1); + } + } + + if (result.length > 1) { + qsort( + result.functionIDs, + result.length, + sizeof(WasmFunctionID), + wasmFunctionIDsCompareHashes + ); + } + + return result; +} + +void wasmSplitStaticAndDynamicFunctions( + WasmFunctionIDs functionIDs, + WasmFunctionIDs referenceFunctionIDs, + WasmFunctionIDs *staticFunctions, + WasmFunctionIDs *dynamicFunctions +) { + WasmFunctionID* functionID = functionIDs.functionIDs; + WasmFunctionID* lastFunctionID = functionID + functionIDs.length; + + WasmFunctionID* referenceFunctionID = referenceFunctionIDs.functionIDs; + WasmFunctionID* lastReferenceFunctionID = referenceFunctionID + referenceFunctionIDs.length; + + while ( + functionID != lastFunctionID + && referenceFunctionID != lastReferenceFunctionID + ) { + int comparisonResult = wasmFunctionIDsCompareHashes(functionID, referenceFunctionID); + if (comparisonResult < 0) { + /* Function only exists in the module, and not in the reference module, so it's a dynamic function */ + if (!wasmFunctionIDsAppend(dynamicFunctions, *functionID)) { + exit(1); + } + + functionID++; + + } else if (comparisonResult > 0) { + /* Function only exists in the reference module, and not in the module, so skip it */ + referenceFunctionID++; + + } else { + /* comparisonResult == 0 */ + /* Function exists in both modules, so it's a static function */ + if (!wasmFunctionIDsAppend(staticFunctions, *functionID)) { + exit(1); + } + + functionID++; + referenceFunctionID++; + } + } + + while (functionID != lastFunctionID) { + /* Identifier only exists in the module, and not in the reference module, so it's a dynamic function */ + if (!wasmFunctionIDsAppend(dynamicFunctions, *functionID)) { + exit(1); + } + functionID++; + } +} + int main( int argc, @@ -89,6 +176,7 @@ main( ) { U32 threadCount = 0; char* modulePath = NULL; + char* referenceModulePath = NULL; char* outputPath = NULL; U32 functionsPerFile = 0; bool pretty = false; @@ -157,6 +245,10 @@ main( } break; } + case 'r': { + referenceModulePath = optarg; + break; + } case 'h': { fprintf( stderr, @@ -180,6 +272,7 @@ main( " -g Generate debug information (function names using asm(); #line directives based on DWARF, if available)\n" " -p Generate pretty code\n" " -m Support multiple modules (prefixes function names)\n" + " -r Reference module\n" ); return 0; } @@ -242,15 +335,55 @@ main( WasmModuleReader reader = emptyWasmModuleReader; WasmCWriteModuleOptions writeOptions = emptyWasmCWriteModuleOptions; + WasmFunctionIDs functionIDs = emptyWasmFunctionIDs; + + WasmFunctionIDs staticFunctionIDs = emptyWasmFunctionIDs; + WasmFunctionIDs dynamicFunctionIDs = emptyWasmFunctionIDs; + if (!readWasmBinary(modulePath, &reader, debug)) { return 1; } + functionIDs = wasmSortedFunctionIDs(reader.module->functions); + + if (referenceModulePath != NULL) { + WasmModuleReader referenceReader = emptyWasmModuleReader; + WasmFunctionIDs referenceFunctionIDs = emptyWasmFunctionIDs; + + size_t total = 0; + + if (!readWasmBinary(referenceModulePath, &referenceReader, false)) { + return 1; + } + + referenceFunctionIDs = wasmSortedFunctionIDs(referenceReader.module->functions); + + wasmSplitStaticAndDynamicFunctions( + functionIDs, + referenceFunctionIDs, + &staticFunctionIDs, + &dynamicFunctionIDs + ); + + total = dynamicFunctionIDs.length + staticFunctionIDs.length; + + fprintf( + stderr, + "w2c2: %lu of %lu functions are dynamic (%.2f%%)\n", + dynamicFunctionIDs.length, + total, + (float)dynamicFunctionIDs.length / (float)total * 100.0 + ); + } else { + staticFunctionIDs = functionIDs; + dynamicFunctionIDs = emptyWasmFunctionIDs; + } + if (functionsPerFile == 0) { functionsPerFile = reader.module->functions.count; } if (functionsPerFile == 0) { - functionsPerFile = 1; + functionsPerFile = UINT32_MAX; } writeOptions.outputPath = outputPath; @@ -261,7 +394,13 @@ main( writeOptions.multipleModules = multipleModules; writeOptions.dataSegmentMode = dataSegmentMode; - if (!wasmCWriteModule(reader.module, moduleName, writeOptions)) { + if (!wasmCWriteModule( + reader.module, + moduleName, + writeOptions, + staticFunctionIDs, + dynamicFunctionIDs + )) { fprintf(stderr, "w2c2: failed to compile\n"); return 1; } diff --git a/w2c2/reader.c b/w2c2/reader.c index 6a916e39..4a54b965 100644 --- a/w2c2/reader.c +++ b/w2c2/reader.c @@ -1,6 +1,7 @@ #include #include #include + #include "reader.h" #include "section.h" #include "opcode.h" @@ -10,6 +11,7 @@ #include "elementsegment.h" #include "debug.h" #include "name.h" +#include "sha1.h" static const U8 wasmMagic[] = { 0x00, 0x61, 0x73, 0x6D, @@ -1369,6 +1371,8 @@ wasmReadCodeSection( { const U8* localsDeclarationsOffset = reader->buffer.data; + SHA1(localsDeclarationsOffset, codeSize, function->hash); + if (!wasmReadCodeLocalsDeclarations(reader, &function->localsDeclarations)) { static WasmModuleReaderError wasmModuleReaderError = { wasmModuleReaderInvalidCodeSectionLocalsDeclarations diff --git a/w2c2/sha1.c b/w2c2/sha1.c new file mode 100644 index 00000000..d7914a3c --- /dev/null +++ b/w2c2/sha1.c @@ -0,0 +1,188 @@ +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + * + * Test Vectors (from FIPS PUB 180-1) + * "abc" + * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + * A million repetitions of "a" + * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F + */ + +#include "w2c2_base.h" +#include "sha1.h" + +#define SHA1_BLOCK_LENGTH 64 + +typedef struct { + uint32_t state[5]; + uint64_t count; + uint8_t buffer[SHA1_BLOCK_LENGTH]; +} SHA1_CTX; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* + * blk0() and blk() perform the initial expand. + * I got the idea of expanding during the round function from SSLeay + */ +#if WASM_ENDIAN == WASM_LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif + +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* + * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 + */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +typedef union { + uint8_t c[64]; + uint32_t l[16]; +} CHAR64LONG16; + +/* + * Hash a single 512-bit block. This is the core of the algorithm. + */ +static +void +SHA1Transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH]) +{ + uint32_t a, b, c, d, e; + uint8_t workspace[SHA1_BLOCK_LENGTH]; + CHAR64LONG16 *block = (CHAR64LONG16 *)workspace; + + (void)memcpy(block, buffer, SHA1_BLOCK_LENGTH); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + +/* + * SHA1Init - Initialize new context + */ +static +void +SHA1Init(SHA1_CTX *context) +{ + + /* SHA1 initialization constants */ + context->count = 0; + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; +} + +/* + * Run your data through this. + */ +static +void +SHA1Update(SHA1_CTX *context, const uint8_t *data, size_t len) +{ + size_t i, j; + + j = (size_t)((context->count >> 3) & 63); + context->count += ((uint64_t)len << 3); + if ((j + len) > 63) { + (void)memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) + SHA1Transform(context->state, (uint8_t *)&data[i]); + j = 0; + } else { + i = 0; + } + (void)memcpy(&context->buffer[j], &data[i], len - i); +} + +/* + * Add padding and return the message digest. + */ +static +void +SHA1Pad(SHA1_CTX *context) +{ + uint8_t finalcount[8]; + unsigned int i; + + for (i = 0; i < 8; i++) { + finalcount[i] = (uint8_t)((context->count >> + ((7 - (i & 7)) * 8)) & 255); /* Endian independent */ + } + SHA1Update(context, (uint8_t *)"\200", 1); + while ((context->count & 504) != 448) + SHA1Update(context, (uint8_t *)"\0", 1); + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ +} + +static +void +SHA1Final(uint8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context) +{ + unsigned int i; + + SHA1Pad(context); + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { + digest[i] = (uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + memset(context, 0, sizeof(*context)); +} + +void SHA1(const uint8_t *data, size_t count, uint8_t *result) { + SHA1_CTX context; + SHA1Init(&context); + SHA1Update(&context, data, count); + SHA1Final(result, &context); +} diff --git a/w2c2/sha1.h b/w2c2/sha1.h new file mode 100644 index 00000000..e2ed8c0e --- /dev/null +++ b/w2c2/sha1.h @@ -0,0 +1,21 @@ +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + */ + +#ifndef W2C2_SHA1_H +#define W2C2_SHA1_H + +#include "w2c2_base.h" + +#define SHA1_DIGEST_LENGTH 20 + +#define SHA1_DIGEST_EMPTY { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ +} + +void SHA1(const unsigned char *data, size_t count, unsigned char *result); + +#endif /* W2C2_SHA1_H */ diff --git a/w2c2/sha1_test.c b/w2c2/sha1_test.c new file mode 100644 index 00000000..28276845 --- /dev/null +++ b/w2c2/sha1_test.c @@ -0,0 +1,47 @@ +#include +#include "sha1_test.h" +#include "sha1.h" + +void +testSHA1(void) { + + { + unsigned char actual[SHA1_DIGEST_LENGTH] = SHA1_DIGEST_EMPTY; + const char* test = "abc"; + SHA1((unsigned char *)test, strlen(test), actual); + + unsigned char expected[SHA1_DIGEST_LENGTH] = { + 0xa9, 0x99, 0x3e, 0x36, + 0x47, 0x06, 0x81, 0x6a, + 0xba, 0x3e, 0x25, 0x71, + 0x78, 0x50, 0xc2, 0x6c, + 0x9c, 0xd0, 0xd8, 0x9d, + }; + + if (memcmp(actual, expected, SHA1_DIGEST_LENGTH) != 0) { + fprintf(stderr, "FAIL testSHA1\n"); + return; + } + } + + { + unsigned char actual[SHA1_DIGEST_LENGTH] = SHA1_DIGEST_EMPTY; + const char* test = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + SHA1((unsigned char *)test, strlen(test), actual); + + unsigned char expected[SHA1_DIGEST_LENGTH] = { + 0x84, 0x98, 0x3e, 0x44, + 0x1c, 0x3b, 0xd2, 0x6e, + 0xba, 0xae, 0x4a, 0xa1, + 0xf9, 0x51, 0x29, 0xe5, + 0xe5, 0x46, 0x70, 0xf1 + }; + + if (memcmp(actual, expected, SHA1_DIGEST_LENGTH) != 0) { + fprintf(stderr, "FAIL testSHA1\n"); + return; + } + } + + fprintf(stderr, "PASS testSHA1\n"); +} diff --git a/w2c2/sha1_test.h b/w2c2/sha1_test.h new file mode 100644 index 00000000..2a94dc13 --- /dev/null +++ b/w2c2/sha1_test.h @@ -0,0 +1,7 @@ +#ifndef W2C2_SHA1_TEST_H +#define W2C2_SHA1_TEST_H + +void +testSHA1(void); + +#endif /* W2C2_SHA1_TEST_H */ diff --git a/w2c2/test.c b/w2c2/test.c index 361ed369..f8727e91 100644 --- a/w2c2/test.c +++ b/w2c2/test.c @@ -2,6 +2,7 @@ #include "stringbuilder_test.h" #include "typestack_test.h" #include "opcode_test.h" +#include "sha1_test.h" int main(void) { @@ -10,5 +11,6 @@ main(void) { testStringBuilder(); testTypeStack(); testOpcodes(); + testSHA1(); return 0; } diff --git a/w2c2/w2c2_base.h b/w2c2/w2c2_base.h index 286bdf5a..40cc799c 100644 --- a/w2c2/w2c2_base.h +++ b/w2c2/w2c2_base.h @@ -841,7 +841,7 @@ DEFINE_STORE32(i64_store32, U32, U64) #if WASM_ENDIAN == WASM_LITTLE_ENDIAN #define DEFINE_SWAP(size, suffix, type) \ - static W2C2_INLINE void swap_ ## suffix(type* v) {} + static W2C2_INLINE void swap_ ## suffix(type* v) { (void)v; } #elif WASM_ENDIAN == WASM_BIG_ENDIAN From 06d1eb58736d75d2a991e8a8d413da71935fbeff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sun, 5 Nov 2023 14:35:47 -0800 Subject: [PATCH 2/8] prefix static and dynamic files --- w2c2/c.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/w2c2/c.c b/w2c2/c.c index 4aa4ee09..4b4b2b5e 100644 --- a/w2c2/c.c +++ b/w2c2/c.c @@ -4722,6 +4722,7 @@ wasmCWriteImplementationFile( const char* moduleName, const char* headerName, WasmDebugLines* debugLines, + char filePrefix, U32 fileIndex, U32 functionsPerFile, U32 startFunctionIDIndex, @@ -4731,7 +4732,7 @@ wasmCWriteImplementationFile( bool multipleModules ) { FILE* file = NULL; - char filename[13]; + char filename[14]; U32 functionCount = (U32)functionIDs.length; U32 endFunctionIDIndex = startFunctionIDIndex + (U32)functionsPerFile; @@ -4744,7 +4745,7 @@ wasmCWriteImplementationFile( return true; } - sprintf(filename, "%010u.c", fileIndex); + sprintf(filename, "%c%010u.c", filePrefix, fileIndex); file = fopen(filename, "w"); if (file == NULL) { fprintf( @@ -4787,6 +4788,7 @@ wasmCWriteImplementationFile( #if HAS_PTHREAD typedef struct WasmCImplementationWriterTask { + char filePrefix; U32 fileIndex; U32 functionsPerFile; const WasmModule* module; @@ -4798,6 +4800,7 @@ typedef struct WasmCImplementationWriterTask { bool debug; bool multipleModules; bool result; + WasmDebugLines *debugLines; } WasmCImplementationWriterTask; typedef struct WasmCImplementationConcurrentWriter { @@ -4861,6 +4864,7 @@ wasmCImplementationWriterThread( const WasmModule* module = task->module; const char* moduleName = task->moduleName; const char* headerName = task->headerName; + char filePrefix = task->filePrefix; U32 fileIndex = task->fileIndex; U32 functionsPerFile = task->functionsPerFile; U32 startFunctionIDIndex = task->startFunctionIDIndex; @@ -4868,6 +4872,7 @@ wasmCImplementationWriterThread( bool pretty = task->pretty; bool debug = task->debug; bool multipleModules = task->multipleModules; + WasmDebugLines* debugLines = task->debugLines; writer->task = NULL; @@ -4878,7 +4883,8 @@ wasmCImplementationWriterThread( module, moduleName, headerName, - NULL, + debugLines, + filePrefix, fileIndex, functionsPerFile, startFunctionIDIndex, @@ -4914,11 +4920,12 @@ wasmCWriteModuleImplementationFiles( const char* moduleName, const char* headerName, WasmFunctionIDs functionIDs, - U32* fileIndex, + char filePrefix, WasmCWriteModuleOptions options ) { WasmDebugLines debugLines = module->debugLines; + U32 fileIndex = 0; size_t functionCount = functionIDs.length; U32 functionsPerFile = options.functionsPerFile; size_t fileCount = 0; @@ -4928,14 +4935,14 @@ wasmCWriteModuleImplementationFiles( fileCount = 1 + (functionCount - 1) / functionsPerFile; { - size_t totalFileCount = *fileIndex + fileCount; - U32 startFunctionIDIndex = 0; #if HAS_PTHREAD U32 threadCount = options.threadCount; pthread_t* threads = calloc(threadCount * sizeof(pthread_t), 1); U32 jobIndex = 0; + bool setDebugLines = options.debug && options.threadCount == 1; + WasmCImplementationConcurrentWriter writer = wasmCImplementationConcurrentWriterNew(); WasmCImplementationWriterTask task; @@ -4965,11 +4972,8 @@ wasmCWriteModuleImplementationFiles( } #endif /* HAS_PTHREAD */ - for (; - *fileIndex < totalFileCount; - (*fileIndex)++, - startFunctionIDIndex += functionsPerFile - ) { + for (; fileIndex < fileCount; fileIndex++) { + U32 startFunctionIDIndex = fileIndex * functionsPerFile; #if HAS_PTHREAD pthread_mutex_lock(&writer.mutex); @@ -4980,9 +4984,15 @@ wasmCWriteModuleImplementationFiles( ); } - task.fileIndex = *fileIndex; + task.filePrefix = filePrefix; + task.fileIndex = fileIndex; task.startFunctionIDIndex = startFunctionIDIndex; task.functionIDs = functionIDs; + if (setDebugLines) { + task.debugLines = &debugLines; + } else { + task.debugLines = NULL; + } writer.task = &task; @@ -4995,7 +5005,8 @@ wasmCWriteModuleImplementationFiles( moduleName, headerName, &debugLines, - *fileIndex, + filePrefix, + fileIndex, functionsPerFile, startFunctionIDIndex, functionIDs, @@ -5049,8 +5060,6 @@ wasmCWriteModuleImplementation( WasmFunctionIDs dynamicFunctionIDs, WasmCWriteModuleOptions options ) { - U32 fileIndex = 0; - /* Create file */ FILE *file = NULL; @@ -5074,7 +5083,7 @@ wasmCWriteModuleImplementation( moduleName, headerName, staticFunctionIDs, - &fileIndex, + 's', options )) @@ -5083,7 +5092,7 @@ wasmCWriteModuleImplementation( moduleName, headerName, dynamicFunctionIDs, - &fileIndex, + 'd', options )) From f1dc205344297af3e8b9ebd290dc1411bb7136da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sun, 5 Nov 2023 15:11:51 -0800 Subject: [PATCH 3/8] add option to clean implementation files --- w2c2/c.c | 2 +- w2c2/c.h | 2 ++ w2c2/main.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/w2c2/c.c b/w2c2/c.c index 4b4b2b5e..2429404a 100644 --- a/w2c2/c.c +++ b/w2c2/c.c @@ -4732,7 +4732,7 @@ wasmCWriteImplementationFile( bool multipleModules ) { FILE* file = NULL; - char filename[14]; + char filename[W2C2_IMPL_FILENAME_LENGTH+1]; U32 functionCount = (U32)functionIDs.length; U32 endFunctionIDIndex = startFunctionIDIndex + (U32)functionsPerFile; diff --git a/w2c2/c.h b/w2c2/c.h index 1070a3de..a712304b 100644 --- a/w2c2/c.h +++ b/w2c2/c.h @@ -4,6 +4,8 @@ #include "w2c2_base.h" #include "module.h" +#define W2C2_IMPL_FILENAME_LENGTH 13 + typedef struct WasmCWriteModuleOptions { const char* outputPath; U32 threadCount; diff --git a/w2c2/main.c b/w2c2/main.c index 5c5445d7..7af1de61 100644 --- a/w2c2/main.c +++ b/w2c2/main.c @@ -11,6 +11,8 @@ #endif #if HAS_GETOPT #include +#include + #else #include "getopt_impl.h" #endif /* HAS_GETOPT */ @@ -22,9 +24,9 @@ #include "stringbuilder.h" #if HAS_PTHREAD -static char* const optString = "t:f:d:r:pgmh"; +static char* const optString = "t:f:d:r:pgmch"; #else -static char* const optString = "f:d:r:pgmh"; +static char* const optString = "f:d:r:pgmch"; #endif /* HAS_PTHREAD */ static @@ -169,6 +171,46 @@ void wasmSplitStaticAndDynamicFunctions( } } +static +void +cleanImplementationFiles(void) { + glob_t globbuf; + size_t pathIndex = 0; + int globResult = glob("[sd]*.c", GLOB_NOSORT, NULL, &globbuf); + if (globResult != 0) { + if (globResult != GLOB_NOMATCH) { + fprintf(stderr, "w2c2: failed to glob files to clean\n"); + } + return; + } + + for (; pathIndex < globbuf.gl_pathc; pathIndex++) { + int pathCharIndex = 1; + bool allDigits = true; + + char *path = globbuf.gl_pathv[pathIndex]; + size_t pathLength = strlen(path); + if (pathLength != W2C2_IMPL_FILENAME_LENGTH) { + continue; + } + + for (; pathCharIndex < pathLength - 2; pathCharIndex++) { + char c = path[pathCharIndex]; + if (c < '0' || c > '9') { + allDigits = false; + break; + } + } + if (!allDigits) { + continue; + } + + if (remove(path) != 0) { + fprintf(stderr, "w2c2: failed to remove file %s\n", path); + } + } +} + int main( int argc, @@ -184,6 +226,7 @@ main( bool multipleModules = false; WasmDataSegmentMode dataSegmentMode = wasmDataSegmentModeArrays; char moduleName[PATH_MAX]; + bool clean = false; int index = 0; int c = -1; @@ -214,6 +257,10 @@ main( multipleModules = true; break; } + case 'c': { + clean = true; + break; + } case 'd': { if (strcmp(optarg, "arrays") == 0) { dataSegmentMode = wasmDataSegmentModeArrays; @@ -331,6 +378,10 @@ main( getPathModuleName(moduleName, modulePath); + if (clean) { + cleanImplementationFiles(); + } + { WasmModuleReader reader = emptyWasmModuleReader; WasmCWriteModuleOptions writeOptions = emptyWasmCWriteModuleOptions; From 6196dc5c2d038d5e9525be956b90525b12ce7431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 6 Nov 2023 07:16:44 -0800 Subject: [PATCH 4/8] keep writing function implementations into main file by default --- w2c2/c.c | 52 ++++++++++++++++++++++++++++++++++++---------------- w2c2/main.c | 8 ++++---- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/w2c2/c.c b/w2c2/c.c index 2429404a..63827817 100644 --- a/w2c2/c.c +++ b/w2c2/c.c @@ -5078,23 +5078,43 @@ wasmCWriteModuleImplementation( /* Write implementations */ - MUST (wasmCWriteModuleImplementationFiles( - module, - moduleName, - headerName, - staticFunctionIDs, - 's', - options - )) + if (options.functionsPerFile >= module->functions.count + && dynamicFunctionIDs.length == 0) + { + WasmDebugLines debugLines = module->debugLines; - MUST (wasmCWriteModuleImplementationFiles( - module, - moduleName, - headerName, - dynamicFunctionIDs, - 'd', - options - )) + MUST (wasmCWriteFunctionImplementations( + file, + module, + moduleName, + &debugLines, + 0, + (U32)staticFunctionIDs.length, + staticFunctionIDs, + options.pretty, + options.debug, + options.multipleModules + )) + } else { + + MUST (wasmCWriteModuleImplementationFiles( + module, + moduleName, + headerName, + staticFunctionIDs, + 's', + options + )) + + MUST (wasmCWriteModuleImplementationFiles( + module, + moduleName, + headerName, + dynamicFunctionIDs, + 'd', + options + )) + } /* Write initializations code */ diff --git a/w2c2/main.c b/w2c2/main.c index 7af1de61..e80e7957 100644 --- a/w2c2/main.c +++ b/w2c2/main.c @@ -410,10 +410,10 @@ main( referenceFunctionIDs = wasmSortedFunctionIDs(referenceReader.module->functions); wasmSplitStaticAndDynamicFunctions( - functionIDs, - referenceFunctionIDs, - &staticFunctionIDs, - &dynamicFunctionIDs + functionIDs, + referenceFunctionIDs, + &staticFunctionIDs, + &dynamicFunctionIDs ); total = dynamicFunctionIDs.length + staticFunctionIDs.length; From 87bd4da802ac7f046f2e5b90f90cd13dbfaf0d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 8 Nov 2023 22:48:05 -0800 Subject: [PATCH 5/8] provide alternative file scanning implementation on Windows --- w2c2/CMakeLists.txt | 5 +++++ w2c2/main.c | 49 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/w2c2/CMakeLists.txt b/w2c2/CMakeLists.txt index db22b7da..c5f27faa 100644 --- a/w2c2/CMakeLists.txt +++ b/w2c2/CMakeLists.txt @@ -22,6 +22,7 @@ include(CheckIncludeFile) check_include_file(getopt.h HAVE_GETOPT_H) check_include_file(libgen.h HAVE_LIBGEN_H) check_include_file(unistd.h HAVE_UNISTD_H) +check_include_file(glob.h HAVE_GLOB_H) include(CheckSymbolExists) check_symbol_exists(strdup string.h HAVE_STRDUP) @@ -77,6 +78,10 @@ foreach(TARGET w2c2 w2c2_test) target_compile_definitions(${TARGET} PUBLIC HAS_STRDUP=1) endif() + if(HAVE_GLOB_H) + target_compile_definitions(${TARGET} PUBLIC HAS_GLOB=1) + endif() + if(MSVC) target_compile_definitions(${TARGET} PUBLIC _CRT_SECURE_NO_DEPRECATE) endif() diff --git a/w2c2/main.c b/w2c2/main.c index e80e7957..751ffe10 100644 --- a/w2c2/main.c +++ b/w2c2/main.c @@ -11,8 +11,6 @@ #endif #if HAS_GETOPT #include -#include - #else #include "getopt_impl.h" #endif /* HAS_GETOPT */ @@ -29,6 +27,14 @@ static char* const optString = "t:f:d:r:pgmch"; static char* const optString = "f:d:r:pgmch"; #endif /* HAS_PTHREAD */ +#if HAS_GLOB +#include +#endif /* HAS_GLOB */ + +#if _WIN32 +#include +#endif + static bool readWasmBinary( @@ -174,9 +180,11 @@ void wasmSplitStaticAndDynamicFunctions( static void cleanImplementationFiles(void) { + char* path = NULL; +#if HAS_GLOB glob_t globbuf; size_t pathIndex = 0; - int globResult = glob("[sd]*.c", GLOB_NOSORT, NULL, &globbuf); + int globResult = glob("*.c", GLOB_NOSORT, NULL, &globbuf); if (globResult != 0) { if (globResult != GLOB_NOMATCH) { fprintf(stderr, "w2c2: failed to glob files to clean\n"); @@ -185,16 +193,34 @@ cleanImplementationFiles(void) { } for (; pathIndex < globbuf.gl_pathc; pathIndex++) { - int pathCharIndex = 1; + path = globbuf.gl_pathv[pathIndex]; +#elif _WIN32 + WIN32_FIND_DATA findFileData; + HANDLE hFind = FindFirstFile("*.c", &findFileData); + if (hFind == INVALID_HANDLE_VALUE) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + fprintf(stderr, "w2c2: failed to find files to clean\n"); + } + return; + } + do { + path = findFileData.cFileName; +#else +#error "Unable to find files" +#endif + int pathCharIndex = 0; bool allDigits = true; - char *path = globbuf.gl_pathv[pathIndex]; size_t pathLength = strlen(path); if (pathLength != W2C2_IMPL_FILENAME_LENGTH) { continue; } - for (; pathCharIndex < pathLength - 2; pathCharIndex++) { + if (path[pathCharIndex] != 'd' && path[pathCharIndex] != 's') { + continue; + } + + for (pathCharIndex = 1; pathCharIndex < pathLength - 2; pathCharIndex++) { char c = path[pathCharIndex]; if (c < '0' || c > '9') { allDigits = false; @@ -205,10 +231,21 @@ cleanImplementationFiles(void) { continue; } + fprintf(stderr, "w2c2: cleaning file: %s\n", path); + if (remove(path) != 0) { fprintf(stderr, "w2c2: failed to remove file %s\n", path); } } +#if _WIN32 + while (FindNextFile(hFind, &findFileData) != 0); +#endif + +#if HAS_GLOB + globfree(&globbuf); +#elif _WIN32 + FindClose(hFind); +#endif } int From a0ef57e825527e861e2089ee51581fd14f0e5d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 8 Nov 2023 22:48:23 -0800 Subject: [PATCH 6/8] move declarations --- w2c2/sha1_test.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/w2c2/sha1_test.c b/w2c2/sha1_test.c index 28276845..499fb8be 100644 --- a/w2c2/sha1_test.c +++ b/w2c2/sha1_test.c @@ -8,7 +8,6 @@ testSHA1(void) { { unsigned char actual[SHA1_DIGEST_LENGTH] = SHA1_DIGEST_EMPTY; const char* test = "abc"; - SHA1((unsigned char *)test, strlen(test), actual); unsigned char expected[SHA1_DIGEST_LENGTH] = { 0xa9, 0x99, 0x3e, 0x36, @@ -18,6 +17,8 @@ testSHA1(void) { 0x9c, 0xd0, 0xd8, 0x9d, }; + SHA1((unsigned char*)test, strlen(test), actual); + if (memcmp(actual, expected, SHA1_DIGEST_LENGTH) != 0) { fprintf(stderr, "FAIL testSHA1\n"); return; @@ -27,7 +28,6 @@ testSHA1(void) { { unsigned char actual[SHA1_DIGEST_LENGTH] = SHA1_DIGEST_EMPTY; const char* test = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - SHA1((unsigned char *)test, strlen(test), actual); unsigned char expected[SHA1_DIGEST_LENGTH] = { 0x84, 0x98, 0x3e, 0x44, @@ -37,6 +37,8 @@ testSHA1(void) { 0xe5, 0x46, 0x70, 0xf1 }; + SHA1((unsigned char*)test, strlen(test), actual); + if (memcmp(actual, expected, SHA1_DIGEST_LENGTH) != 0) { fprintf(stderr, "FAIL testSHA1\n"); return; From 0138a40e4a90dee670dc9a8aa097998a2fcadb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 8 Nov 2023 22:53:54 -0800 Subject: [PATCH 7/8] add HAS_GLOB feature to Makefile --- w2c2/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/w2c2/Makefile b/w2c2/Makefile index 91dd58c5..a04d3fcc 100644 --- a/w2c2/Makefile +++ b/w2c2/Makefile @@ -27,7 +27,8 @@ CFLAGS += -std=c89 $(WARNS) # - unistd.h # - libgen.h # - strdup -FEATURES ?= threads getopt unistd libgen strdup +# - glob +FEATURES ?= threads getopt unistd libgen strdup glob ifeq ($(UNAME),Windows) OUTPUT := w2c2.exe @@ -62,6 +63,10 @@ ifneq (,$(findstring strdup,$(FEATURES))) CFLAGS += -DHAS_STRDUP=1 endif +ifneq (,$(findstring glob,$(FEATURES))) + CFLAGS += -DHAS_GLOB=1 +endif + ifneq (,$(findstring debugging,$(FEATURES))) CFLAGS += -DHAS_LIBDWARF=1 LDFLAGS += -ldwarf From 0e3b538e8ea4472d33b8b7dc9ef7e38a916e6b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 8 Nov 2023 22:57:10 -0800 Subject: [PATCH 8/8] add glob feature to CI --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 78d6d00c..76647819 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,7 +77,7 @@ jobs: env: LDFLAGS: -static working-directory: ./w2c2 - run: make BUILD=${{ matrix.build }} FEATURES="unistd libgen getopt ${{ matrix.threads && 'threads' || '' }}" + run: make BUILD=${{ matrix.build }} FEATURES="unistd libgen getopt glob ${{ matrix.threads && 'threads' || '' }}" - if: steps.changes.outputs.w2c2 == 'true' name: Run w2c2 tests env: @@ -114,7 +114,7 @@ jobs: - if: steps.changes.outputs.w2c2 == 'true' name: Build w2c2 working-directory: ./w2c2 - run: make BUILD=${{ matrix.build }} FEATURES="unistd libgen getopt ${{ matrix.threads && 'threads' || '' }}" + run: make BUILD=${{ matrix.build }} FEATURES="unistd libgen getopt glob ${{ matrix.threads && 'threads' || '' }}" - if: steps.changes.outputs.w2c2 == 'true' name: Run tests working-directory: ./tests