Compare commits

...

6 Commits

Author SHA1 Message Date
Rangi
1eb4eb3339 Reuse the usage.name for printing version info 2025-11-18 22:32:45 -05:00
Rangi
a3d3e1525a Fix RGBLINK object type detection 2025-11-18 22:01:43 -05:00
Rangi
3553c9c4da Fix RGBLINK evaluation of undefined RPN symbols
This was the only RPN case to not assign a deliberate value
in all possible branches.

Fixes #1858
2025-11-18 16:40:24 -05:00
Rangi
5c2c893ced Refactor getSectionDescription in src/link/assign.cpp 2025-11-16 17:37:01 -05:00
Rangi
0f266d1c66 Specify more ASan options (#1860) 2025-11-16 17:11:09 -05:00
Rangi
8ab4602ae5 Add -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG to develop builds (#1859) 2025-11-16 13:11:08 -05:00
12 changed files with 63 additions and 70 deletions

View File

@@ -49,7 +49,7 @@ else()
-fsanitize=float-divide-by-zero)
add_compile_options(${SAN_FLAGS})
add_link_options(${SAN_FLAGS})
add_definitions(-D_GLIBCXX_ASSERTIONS)
add_definitions(-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)
# A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ${CMAKE_CXX_FLAGS_DEBUG}"
CACHE STRING "" FORCE)

View File

@@ -222,8 +222,8 @@ develop:
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 \
-Wno-format-nonliteral -Wno-strict-overflow -Wno-unused-but-set-variable \
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare -Wvla \
-D_GLIBCXX_ASSERTIONS -fsanitize=address -fsanitize=undefined \
-fsanitize=float-divide-by-zero" \
-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG \
-fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero" \
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# Target used in development to debug with gdb.

View File

@@ -296,7 +296,7 @@ static void parseArg(int ch, char *arg) {
// LCOV_EXCL_START
case 'V':
printf("rgbasm %s\n", get_package_version_string());
printf("%s %s\n", usage.name.c_str(), get_package_version_string());
exit(0);
case 'v':
@@ -381,7 +381,7 @@ static void verboseOutputConfig() {
style_Set(stderr, STYLE_MAGENTA, false);
fprintf(stderr, "rgbasm %s\n", get_package_version_string());
fprintf(stderr, "%s %s\n", usage.name.c_str(), get_package_version_string());
printVVVVVVerbosity();

View File

@@ -252,7 +252,7 @@ static void parseArg(int ch, char *arg) {
// LCOV_EXCL_START
case 'V':
printf("rgbfix %s\n", get_package_version_string());
printf("%s %s\n", usage.name.c_str(), get_package_version_string());
exit(0);
case 'v':

View File

@@ -409,7 +409,7 @@ static void parseArg(int ch, char *arg) {
// LCOV_EXCL_START
case 'V':
printf("rgbgfx %s\n", get_package_version_string());
printf("%s %s\n", usage.name.c_str(), get_package_version_string());
exit(0);
case 'v':
@@ -481,7 +481,7 @@ static void verboseOutputConfig() {
style_Set(stderr, STYLE_MAGENTA, false);
fprintf(stderr, "rgbgfx %s\n", get_package_version_string());
fprintf(stderr, "%s %s\n", usage.name.c_str(), get_package_version_string());
printVVVVVVerbosity();

View File

@@ -208,50 +208,37 @@ static std::optional<size_t> getPlacement(Section const &section, MemoryLocation
}
static std::string getSectionDescription(Section const &section) {
std::string where;
char bank[8], addr[8], mask[8], offset[8];
std::string description =
"\"" + section.name + "\" (" + sectionTypeInfo[section.type].name + " section) ";
if (section.isBankFixed && sectTypeBanks(section.type) != 1) {
char bank[8];
snprintf(bank, sizeof(bank), "%02" PRIx32, section.bank);
}
if (section.isAddressFixed) {
char addr[8];
snprintf(addr, sizeof(addr), "%04" PRIx16, section.org);
description = description + "at $" + bank + ":" + addr;
} else if (section.isAlignFixed) {
char mask[8];
snprintf(mask, sizeof(mask), "%" PRIx16, static_cast<uint16_t>(~section.alignMask));
description = description + "in bank $" + bank + " with align mask $" + mask;
} else {
description = description + "in bank $" + bank;
}
if (section.isAlignFixed) {
} else {
if (section.isAddressFixed) {
char addr[8];
snprintf(addr, sizeof(addr), "%04" PRIx16, section.org);
description = description + "at address $" + addr;
} else if (section.isAlignFixed) {
char mask[8], offset[8];
snprintf(mask, sizeof(mask), "%" PRIx16, static_cast<uint16_t>(~section.alignMask));
snprintf(offset, sizeof(offset), "%" PRIx16, section.alignOfs);
}
if (section.isBankFixed && sectTypeBanks(section.type) != 1) {
if (section.isAddressFixed) {
where = "at $";
where += bank;
where += ":";
where += addr;
} else if (section.isAlignFixed) {
where = "in bank $";
where += bank;
where += " with align mask $";
where += mask;
description = description + "with align mask $" + mask + " and offset $" + offset;
} else {
where = "in bank $";
where += bank;
}
} else {
if (section.isAddressFixed) {
where = "at address $";
where += addr;
} else if (section.isAlignFixed) {
where = "with align mask $";
where += mask;
where += " and offset $";
where += offset;
} else {
where = "anywhere";
description = description + "anywhere";
}
}
return where;
return description;
}
// Places a section in a suitable location, or error out if it fails to.
@@ -310,19 +297,11 @@ static void placeSection(Section &section) {
if (!section.isBankFixed || !section.isAddressFixed) {
// If a section failed to go to several places, nothing we can report
fatal(
"Unable to place \"%s\" (%s section) %s",
section.name.c_str(),
sectionTypeInfo[section.type].name.c_str(),
getSectionDescription(section).c_str()
);
fatal("Unable to place %s", getSectionDescription(section).c_str());
} else if (section.org + section.size > sectTypeEndAddr(section.type) + 1) {
// If the section just can't fit the bank, report that
fatal(
"Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > "
"$%04x)",
section.name.c_str(),
sectionTypeInfo[section.type].name.c_str(),
"Unable to place %s: section runs past end of region ($%04x > $%04x)",
getSectionDescription(section).c_str(),
section.org + section.size,
sectTypeEndAddr(section.type) + 1
@@ -330,9 +309,7 @@ static void placeSection(Section &section) {
} else {
// Otherwise there is overlap with another section
fatal(
"Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
section.name.c_str(),
sectionTypeInfo[section.type].name.c_str(),
"Unable to place %s: section overlaps with \"%s\"",
getSectionDescription(section).c_str(),
out_OverlappingSection(section)->name.c_str()
);

View File

@@ -283,7 +283,7 @@ static void parseArg(int ch, char *arg) {
// LCOV_EXCL_START
case 'V':
printf("rgblink %s\n", get_package_version_string());
printf("%s %s\n", usage.name.c_str(), get_package_version_string());
exit(0);
case 'v':
@@ -330,7 +330,7 @@ static void verboseOutputConfig() {
style_Set(stderr, STYLE_MAGENTA, false);
fprintf(stderr, "rgblink %s\n", get_package_version_string());
fprintf(stderr, "%s %s\n", usage.name.c_str(), get_package_version_string());
printVVVVVVerbosity();

View File

@@ -420,19 +420,15 @@ void obj_ReadFile(std::string const &filePath, size_t fileID) {
}
Defer closeFile{[&] { fclose(file); }};
// First, check if the object is a RGBDS object or a SDCC one. If the first byte is 'R',
// we'll assume it's a RGBDS object file, and otherwise, that it's a SDCC object file.
int c = getc(file);
ungetc(c, file); // Guaranteed to work
switch (c) {
// First, check if the object is a RGBDS object, a SDCC one, or neither.
// A single `ungetc` is guaranteed to work.
switch (ungetc(getc(file), file)) {
case EOF:
fatal("File \"%s\" is empty!", fileName);
case 'R':
break;
default:
case 'X':
case 'D':
case 'Q': {
// This is (probably) a SDCC object file, defer the rest of detection to it.
// Since SDCC does not provide line info, everything will be reported as coming from the
// object file. It's better than nothing.
@@ -450,11 +446,16 @@ void obj_ReadFile(std::string const &filePath, size_t fileID) {
return;
}
// Begin by reading the magic bytes
int matchedElems;
case 'R':
// Check the magic byte signature for a RGB object file.
if (char magic[literal_strlen(RGBDS_OBJECT_VERSION_STRING)];
fread(magic, 1, sizeof(magic), file) == sizeof(magic)
&& !memcmp(magic, RGBDS_OBJECT_VERSION_STRING, sizeof(magic))) {
break;
}
[[fallthrough]];
if (fscanf(file, RGBDS_OBJECT_VERSION_STRING "%n", &matchedElems) == 1
&& matchedElems != literal_strlen(RGBDS_OBJECT_VERSION_STRING)) {
default:
fatal("%s: Not a RGBDS object file", fileName);
}

View File

@@ -437,6 +437,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
} else if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) {
errorAt(patch, "Undefined symbol `%s`", fileSymbols[value].name.c_str());
sym_TraceLocalAliasedSymbols(fileSymbols[value].name);
value = 0;
isError = true;
} else if (std::holds_alternative<Label>(symbol->data)) {
Label const &label = std::get<Label>(symbol->data);

View File

@@ -14,7 +14,13 @@
#if !defined(NDEBUG) && defined(__SANITIZE_ADDRESS__) && !defined(__APPLE__)
extern "C" {
char const *__asan_default_options(void) {
return "detect_leaks=1";
return "detect_leaks=1"
":detect_stack_use_after_return=1"
":detect_invalid_pointer_pairs=2"
":check_initialization_order=1"
":strict_init_order=1"
":strict_string_checks=1"
":print_legend=0";
}
}
#endif

View File

@@ -0,0 +1,3 @@
SECTION "bad", ROM0
ld a, FOO * 256
ld a, BAR * 256

View File

@@ -0,0 +1,5 @@
error: Undefined symbol `BAR`
at rpn-bad-sym-id.asm(3)
error: Undefined symbol `FOO`
at rpn-bad-sym-id.asm(2)
Linking failed with 2 errors