Skip to content

Commit beb4adc

Browse files
committed
Implement const qualifier for global variables
This extends existing .rodata section support to handle const-qualified globals. Now, const initialized variables are placed in read-only memory section instead of writable .data section.
1 parent 4c41726 commit beb4adc

File tree

5 files changed

+127
-8
lines changed

5 files changed

+127
-8
lines changed

src/defs.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ typedef enum {
179179
T_break,
180180
T_default,
181181
T_continue,
182+
T_const, /* const qualifier */
182183
/* C pre-processor directives */
183184
T_cppd_include,
184185
T_cppd_define,
@@ -353,8 +354,9 @@ struct var {
353354
int ptr_level;
354355
bool is_func;
355356
bool is_global;
356-
bool is_initialized; /* true if global variable has initialization */
357-
bool address_taken; /* true if variable address was taken (&var) */
357+
bool is_initialized; /* true if global variable has initialization */
358+
bool is_const_qualified; /* true if variable has const qualifier */
359+
bool address_taken; /* true if variable address was taken (&var) */
358360
int array_size;
359361
int array_dim1, array_dim2; /* first/second dimension size for 2D arrays */
360362
int offset; /* offset from stack or frame, index 0 is reserved */

src/lexer.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
/* Hash table constants */
1414
#define NUM_DIRECTIVES 11
15-
#define NUM_KEYWORDS 16
15+
#define NUM_KEYWORDS 17
1616

1717
/* Token mapping structure for elegant initialization */
1818
typedef struct {
@@ -86,6 +86,7 @@ void lex_init_keywords()
8686
{"default", T_default},
8787
{"continue", T_continue},
8888
{"union", T_union},
89+
{"const", T_const},
8990
};
9091

9192
/* hashmap insertion */
@@ -787,13 +788,15 @@ token_t lex_token_impl(bool aliasing)
787788
keyword = T_case;
788789
break;
789790

790-
case 5: /* 5-letter keywords: while, break, union */
791+
case 5: /* 5-letter keywords: while, break, union, const */
791792
if (token_str[0] == 'w' && !memcmp(token_str, "while", 5))
792793
keyword = T_while;
793794
else if (token_str[0] == 'b' && !memcmp(token_str, "break", 5))
794795
keyword = T_break;
795796
else if (token_str[0] == 'u' && !memcmp(token_str, "union", 5))
796797
keyword = T_union;
798+
else if (token_str[0] == 'c' && !memcmp(token_str, "const", 5))
799+
keyword = T_const;
797800
break;
798801

799802
case 6: /* 6-letter keywords: return, struct, switch, sizeof */

src/parser.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4809,10 +4809,11 @@ void read_func_body(func_t *func)
48094809
}
48104810

48114811
/* if first token is type */
4812-
void read_global_decl(block_t *block)
4812+
void read_global_decl(block_t *block, bool is_const)
48134813
{
48144814
var_t *var = require_var(block);
48154815
var->is_global = true;
4816+
var->is_const_qualified = is_const;
48164817

48174818
/* new function, or variables under parent */
48184819
read_full_var_decl(var, false, false);
@@ -4902,6 +4903,7 @@ void initialize_struct_field(var_t *nv, var_t *v, int offset)
49024903
nv->is_func = false;
49034904
nv->is_global = false;
49044905
nv->is_initialized = false;
4906+
nv->is_const_qualified = false;
49054907
nv->array_size = 0;
49064908
nv->offset = offset;
49074909
nv->init_val = 0;
@@ -4916,6 +4918,11 @@ void read_global_statement(void)
49164918
{
49174919
char token[MAX_ID_LEN];
49184920
block_t *block = GLOBAL_BLOCK; /* global block */
4921+
bool is_const = false;
4922+
4923+
/* Handle const qualifier */
4924+
if (lex_accept(T_const))
4925+
is_const = true;
49194926

49204927
if (lex_accept(T_struct)) {
49214928
int i = 0, size = 0;
@@ -4931,6 +4938,7 @@ void read_global_statement(void)
49314938
/* one or more declarators */
49324939
var_t *var = require_typed_var(block, decl_type);
49334940
var->is_global = true; /* Global struct variable */
4941+
var->is_const_qualified = is_const;
49344942
read_partial_var_decl(var, NULL);
49354943
add_insn(block, GLOBAL_FUNC->bbs, OP_allocat, var, NULL, NULL, 0,
49364944
NULL);
@@ -5228,7 +5236,7 @@ void read_global_statement(void)
52285236
lex_expect(T_semicolon);
52295237
}
52305238
} else if (lex_peek(T_identifier, NULL)) {
5231-
read_global_decl(block);
5239+
read_global_decl(block, is_const);
52325240
} else
52335241
error("Syntax error in global statement");
52345242
}

src/reg-alloc.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,11 @@ void reg_alloc(void)
424424
? align_size(PTR_SIZE * global_insn->rd->array_size)
425425
: align_size(global_insn->rd->array_size *
426426
global_insn->rd->type->size);
427-
elf_data->size += size;
427+
/* Const initialized globals go to .rodata */
428+
if (global_insn->rd->is_const_qualified)
429+
elf_rodata->size += size;
430+
else
431+
elf_data->size += size;
428432
} else {
429433
int size =
430434
global_insn->rd->ptr_level
@@ -460,7 +464,11 @@ void reg_alloc(void)
460464

461465
/* Track section sizes for ELF generation */
462466
if (global_insn->rd->is_initialized) {
463-
elf_data->size += size;
467+
/* Const initialized globals go to .rodata */
468+
if (global_insn->rd->is_const_qualified)
469+
elf_rodata->size += size;
470+
else
471+
elf_data->size += size;
464472
} else {
465473
elf_bss_size += size;
466474
}

tests/driver.sh

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,6 +1711,104 @@ int main()
17111711
}
17121712
EOF
17131713

1714+
# Category: Const Qualifier
1715+
begin_category "Const Qualifier" "Testing const keyword for global variables"
1716+
1717+
# Basic const global scalar variables
1718+
try_ 42 << EOF
1719+
const int readonly_value = 42;
1720+
int main() {
1721+
return readonly_value;
1722+
}
1723+
EOF
1724+
1725+
try_ 100 << EOF
1726+
const int max_size = 100;
1727+
int main() {
1728+
return max_size;
1729+
}
1730+
EOF
1731+
1732+
# Multiple const globals
1733+
try_ 42 << EOF
1734+
const int MAGIC_NUMBER = 42;
1735+
const int SPEED_OF_LIGHT = 300000;
1736+
int main() {
1737+
return MAGIC_NUMBER;
1738+
}
1739+
EOF
1740+
1741+
# Mixed const and non-const globals
1742+
try_ 85 << EOF
1743+
const int const_val = 42;
1744+
int regular_val = 43;
1745+
int main() {
1746+
return const_val + regular_val;
1747+
}
1748+
EOF
1749+
1750+
# Const globals with expressions
1751+
try_ 25 << EOF
1752+
const int base = 5;
1753+
const int multiplier = 5;
1754+
int main() {
1755+
return base * multiplier;
1756+
}
1757+
EOF
1758+
1759+
# Const globals with different types
1760+
try_ 65 << EOF
1761+
const char letter = 'A';
1762+
const int number = 0;
1763+
int main() {
1764+
return letter + number; /* 'A' = 65, 65 + 0 = 65 */
1765+
}
1766+
EOF
1767+
1768+
# Verify const globals work with string literals (both in .rodata)
1769+
try_ 0 << EOF
1770+
const int magic_number = 42;
1771+
int main() {
1772+
char *msg = "String in rodata";
1773+
/* Verify string literal and const global both work */
1774+
if (msg[0] != 'S') return 1;
1775+
if (magic_number != 42) return 2;
1776+
return 0;
1777+
}
1778+
EOF
1779+
1780+
# Const globals in arithmetic expressions
1781+
try_ 30 << EOF
1782+
const int x = 10;
1783+
const int y = 20;
1784+
int main() {
1785+
int result = x + y;
1786+
return result;
1787+
}
1788+
EOF
1789+
1790+
# Const globals in conditional expressions
1791+
try_ 1 << EOF
1792+
const int threshold = 50;
1793+
int main() {
1794+
int value = 60;
1795+
return value > threshold ? 1 : 0;
1796+
}
1797+
EOF
1798+
1799+
# Const globals as function parameters (pass by value)
1800+
try_ 100 << EOF
1801+
const int global_const = 50;
1802+
1803+
int double_value(int x) {
1804+
return x * 2;
1805+
}
1806+
1807+
int main() {
1808+
return double_value(global_const);
1809+
}
1810+
EOF
1811+
17141812
# Category: Ternary Operator
17151813
begin_category "Ternary Operator" "Testing conditional ?: operator"
17161814

0 commit comments

Comments
 (0)