If you are being that careful/concerned about memory allocation then you'll almost certainly need to write your own startup code (rather than using the code that Altera's build system includes). This isn't that difficult as you only need to set the %gp and %sp (and maybe %et) registers from code at the cpu's reset entry point before jumping to the first C function.
This can be done from a .S file, but given the small number of instructions I hand assembled them and put them directly into the linker script. This gives something like (edited for inclusion here).
MEMORY
{
code_memory (x) : ORIGIN = 0x8000, LENGTH = 8k
data_memory (rw) : ORIGIN = 0x14000, LENGTH = 48k
}
/* Memory from 0x14000 to 0x24000 is accessible from %gp */
_gp = 128k - 16k;
STACK_SIZE = 1024;
/* Constants for building instructions by hand */
RA_SHIFT = 32 - 5;
RB_SHIFT = RA_SHIFT - 5;
RC_SHIFT = RB_SHIFT - 5;
OP_SHIFT = RC_SHIFT - 6;
IMM16_SHIFT = 6;
SECTIONS
{
/* code - at reset vector */
code : {
/* Instuctions to set %gp */
LONG(0 << RA_SHIFT | 26 << RB_SHIFT | ((_gp + 32768) >> 16) << IMM16_SHIFT | 0x34)
LONG(26 << RA_SHIFT | 26 << RB_SHIFT | (_gp & 0xffff) << IMM16_SHIFT | 0x4)
/* Set %sp by adding affset from %gp */
LONG(26 << RA_SHIFT | 27 << RB_SHIFT | 0x4 | ((stack_top - _gp) & 0xffff) << IMM16_SHIFT)
LONG(main << 4 | 1) /* jmpi main() */
. = 0x20;
/* Add exception (aka interrupt) code here */
....
*(.text)
/* add other sections */
} >code_memory
data : {
stack_limit = .;
. = . + STACK_SIZE;
stack_top = .;
*(.sdata*)
*(.rodata)
/* add other sections */
} >data_memory
}