diff --git a/include/asm/section.hpp b/include/asm/section.hpp index e7a92ef9..3421a0c6 100644 --- a/include/asm/section.hpp +++ b/include/asm/section.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -100,8 +101,7 @@ void sect_RelBytes(uint32_t n, std::vector const &exprs); void sect_RelWord(Expression const &expr, uint32_t pcShift); void sect_RelLong(Expression const &expr, uint32_t pcShift); void sect_PCRelByte(Expression const &expr, uint32_t pcShift); -bool sect_BinaryFile(std::string const &name, uint32_t startPos); -bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length); +bool sect_BinaryFile(std::string const &name, uint32_t startPos, std::optional length); void sect_EndSection(); void sect_PushSection(); diff --git a/src/asm/parser.y b/src/asm/parser.y index dbe8c6e4..8a84f309 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -1035,17 +1035,17 @@ include: incbin: POP_INCBIN string { - if (sect_BinaryFile($2, 0)) { + if (sect_BinaryFile($2, 0, std::nullopt)) { YYACCEPT; } } | POP_INCBIN string COMMA uconst { - if (sect_BinaryFile($2, $4)) { + if (sect_BinaryFile($2, $4, std::nullopt)) { YYACCEPT; } } | POP_INCBIN string COMMA uconst COMMA uconst { - if (sect_BinaryFileSlice($2, $4, $6)) { + if (sect_BinaryFile($2, $4, $6)) { YYACCEPT; } } diff --git a/src/asm/section.cpp b/src/asm/section.cpp index 4e0f081b..3ff28016 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -978,10 +978,13 @@ void sect_PCRelByte(Expression const &expr, uint32_t pcShift) { } } -bool sect_BinaryFile(std::string const &name, uint32_t startPos) { +bool sect_BinaryFile(std::string const &name, uint32_t startPos, std::optional length) { if (!requireCodeSection()) { return false; } + if (length.has_value() && *length == 0) { // Don't even bother with 0-byte slices + return false; + } FILE *file = nullptr; if (std::optional fullPath = fstk_FindFile(name); fullPath) { @@ -1002,6 +1005,16 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) { *fileSize ); return false; + } else if (length.has_value() && *length > *fileSize - startPos) { + error( + "Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32 + " > %" PRIu64 ")", + name.c_str(), + startPos, + *length, + *fileSize + ); + return false; } // The file is seekable; skip to the specified start position fseek(file, startPos, SEEK_SET); @@ -1024,8 +1037,26 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) { // LCOV_EXCL_STOP } - for (int byte; (byte = fgetc(file)) != EOF;) { - writeByte(byte); + if (length.has_value()) { + uint32_t remaining = *length; + for (; remaining; --remaining) { + if (int byte = fgetc(file); byte == EOF) { + break; // LCOV_EXCL_LINE + } else { + writeByte(byte); + } + } + if (remaining > 0 && !ferror(file)) { + error( + "Premature end of `INCBIN` file \"%s\" (%" PRId32 " bytes left to read)", + name.c_str(), + remaining + ); + } + } else { + for (int byte; (byte = fgetc(file)) != EOF;) { + writeByte(byte); + } } if (ferror(file)) { @@ -1036,83 +1067,6 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) { return false; } -bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length) { - if (!requireCodeSection()) { - return false; - } - if (length == 0) { // Don't even bother with 0-byte slices - return false; - } - - FILE *file = nullptr; - if (std::optional fullPath = fstk_FindFile(name); fullPath) { - file = fopen(fullPath->c_str(), "rb"); - } - if (!file) { - return fstk_FileError(name, "`INCBIN`"); - } - Defer closeFile{[&] { xfclose(file); }}; - - if (std::optional fileSize = seekSize(file); fileSize.has_value()) { - if (startPos > *fileSize) { - error( - "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%" PRIu64 - ")", - startPos, - name.c_str(), - *fileSize - ); - return false; - } else if (length > *fileSize - startPos) { - error( - "Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32 - " > %" PRIu64 ")", - name.c_str(), - startPos, - length, - *fileSize - ); - return false; - } - // The file is seekable; skip to the specified start position - fseek(file, startPos, SEEK_SET); - } else { - // LCOV_EXCL_START - if (errno != ESPIPE) { - error( - "Error determining size of `INCBIN` file \"%s\": %s", name.c_str(), strerror(errno) - ); - } - // The file isn't seekable, so we'll just skip bytes one at a time - while (startPos--) { - if (fgetc(file) == EOF) { - error( - "Specified start position is greater than length of file \"%s\"", name.c_str() - ); - return false; - } - } - // LCOV_EXCL_STOP - } - - while (length--) { - if (int byte = fgetc(file); byte != EOF) { - writeByte(byte); - // LCOV_EXCL_START - } else if (ferror(file)) { - error("Error reading `INCBIN` file \"%s\": %s", name.c_str(), strerror(errno)); - } else { - error( - "Premature end of `INCBIN` file \"%s\" (%" PRId32 " bytes left to read)", - name.c_str(), - length + 1 - ); - // LCOV_EXCL_STOP - } - } - return false; -} - void sect_PushSection() { sectionStack.push_front({ .section = currentSection,