[PATCH 0/5] newlib: m68k-atari-dev fixes.

<[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <1759129079498.7.894@webmail-backend-production-5df46479fc-qw6kr>
Collection of bugfixes after feedback from community.

Should only affect the target: m68k-atari-dev.
Mikael Hildenborg (5):
m68k-atari-elf: fixed wrong number of seconds between 1900 and 1980.
m68k-atari-elf: changed stack and heap handling to mimic mintlib.
m68k-atari-elf: updated readme
m68k-atari-elf: proper setup of environment variables and program
arguments.
m68k-atari-elf: specs file declares environ as undefined.

libgloss/m68k/atari/README | 26 +--
libgloss/m68k/atari/atari-crt0.S | 55 +-----
libgloss/m68k/atari/atari-crti.S | 123 +++++++++----
libgloss/m68k/atari/atari-environ.c | 267 +++++++++++++++++++++++++++-
libgloss/m68k/atari/atari-gettod.c | 2 +-
libgloss/m68k/atari/atari-sbrk.c | 18 +-
libgloss/m68k/atari/atari-tos.specs | 2 +-
7 files changed, 389 insertions(+), 104 deletions(-)

--
2.43.0
0001-m68k-atari-elf-fixed-wrong-number-of-seconds-between.patch (text/x-patch, 865 B)
From 82172715c232c6d322af0719cc45514464428ab5 Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Sun, 10 Aug 2025 08:49:23 +0200
Subject: [PATCH 1/5] m68k-atari-elf: fixed wrong number of seconds between
 1900 and 1980.

---
 libgloss/m68k/atari/atari-gettod.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libgloss/m68k/atari/atari-gettod.c b/libgloss/m68k/atari/atari-gettod.c
index 5477916a2..75139ed8c 100644
--- a/libgloss/m68k/atari/atari-gettod.c
+++ b/libgloss/m68k/atari/atari-gettod.c
@@ -14,7 +14,7 @@
 	The code below uses that limitation to simplify the code.
 */
 
-#define SEC_1900_TO_1980 2524521600
+#define SEC_1900_TO_1980 315529200
 #define SEC_1900_TO_MAX 0x7fffffff
 #define SECONDS_IN_A_DAY (24 * 60 * 60)
 #define SEC_JAN_AND_FEB ((31 + 29) * SECONDS_IN_A_DAY)	// In a leap year
-- 
2.43.0
0002-m68k-atari-elf-changed-stack-and-heap-handling-to-mi.patch (text/x-patch, 3.9 KB)
From 44ecacdc9b33379e239c51736eb259ada84feaff Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Wed, 13 Aug 2025 18:15:34 +0200
Subject: [PATCH 2/5] m68k-atari-elf: changed stack and heap handling to mimic
 mintlib.

---
 libgloss/m68k/atari/atari-crti.S | 83 +++++++++++++++++++++-----------
 libgloss/m68k/atari/atari-sbrk.c | 18 +++++--
 2 files changed, 70 insertions(+), 31 deletions(-)

diff --git a/libgloss/m68k/atari/atari-crti.S b/libgloss/m68k/atari/atari-crti.S
index 5e4c13b0e..e11c51cba 100644
--- a/libgloss/m68k/atari/atari-crti.S
+++ b/libgloss/m68k/atari/atari-crti.S
@@ -8,14 +8,12 @@
 #define _fini	__libc_fini_array
 #endif
 
-	.equ	DEFAULT_STACK, 2000
+	.equ	MINKEEP, 0x10000
 
 	.global _BasePage
-	.weak 	_STACK_SIZE
-	.weak 	_HEAP_SIZE
+	.weak 	_stksize
 	.global _HeapPtr
-	.global _HeapBottom
-	.global _HeapTop
+	.global _heapbase
 	.global _atari_4ba_at_prg_start
 	.global __BSS_SEGMENT_END
 
@@ -26,32 +24,62 @@ _init:
 	move.l	4(a7),a0
 	move.l	a0, _BasePage
 
-	| Init stack
+/*
+	Init stack and heap.
+	The size of the stack and heap together is specified in _stksize.
+	The stack is set to point at the top of the reserved memory.
+	The heap is set to point at the bottom of the reserved memory.
+	Usage of _stksize (mintlib functionally compatible):
+		if _stksize is undefined, then all available memory is used.
+		if _stksize is 0, then MINKEEP memory is used.
+		if _stksize > 0 && < 4, then _stksize/4 of all memory is used.
+		if _stksize >= 4, then use that much memory.
+		if _stksize == -1, then all available memory is used.
+		if _stksize < -1, then use -_stksize memory.
+*/
 	lea		__BSS_SEGMENT_END, a2
-	lea		_STACK_SIZE, a1
+	move.l	a2, _heapbase
+	move.l	a2, _HeapPtr
+
+	move.l	4(a0), d1		| mem top
+	sub.l	a2, d1			| free mem
+	lea		_stksize, a1
 	cmpa.w	#0, a1
-	jeq		default_stack_size
-	add.l	(a1), a2
-	jra		stack_size_selected
-default_stack_size:
-	lea		DEFAULT_STACK(a2), a2
-stack_size_selected:
-	move.l	a2, a7
+	jeq		stksize_selected
+	move.l	(a1), d0
+	jeq		stksize_zero
+	jmi		stksize_negative
+stksize_positive:
+	moveq	#4, d2
+	cmp.l	d2, d0
+	jpl		stksize_above_three
+stksize_one_to_three:
+	lsr.l	#2, d1
+	move.l	d1, d2
+1:
+	subq.w	#1, d0
+	jeq		stksize_selected
+	add.l	d2, d1
+	jra		1b
+stksize_zero:
+	move.l	#MINKEEP, d1
+	jra		stksize_selected
+stksize_negative:
+	not.l	d0
+	jeq		stksize_selected	| -1
+	addq.l	#1, d0				| d0 = -_stksize
+stksize_above_three:
+	move.l	d0, d1
+stksize_selected:
 
-	| Init heap
-	move.l	a7, d0
-	move.l	d0, _HeapBottom
-	move.l	d0, _HeapPtr
-	move.l	4(a0), _HeapTop
+	add.l	a2, d1
+	bclr	#0, d1		| even address.
+	move.l	d1, a7
 
-	lea		_HEAP_SIZE, a1
-	cmpa.w	#0, a1
-	jeq		heap_setup_done
-	add.l	(a1), d0
-	sub.l	(a0), d0			| d0 is now the TPA size
+	sub.l	a0, d1		| mem from basepage to top.
 
-	| Program do not want all memory, so we shrink it.
-	move.l	d0, -(a7)
+	| Shrink mem.
+	move.l	d1, -(a7)
 	move.l	a0, -(a7)
 	clr.w	-(a7)
 	move.w	#0x4a, -(a7)	| Mshrink()
@@ -84,7 +112,6 @@ heap_setup_done:
 	.bss
 	.lcomm 	_BasePage, 4
 	.lcomm 	_HeapPtr, 4
-	.lcomm 	_HeapBottom, 4
-	.lcomm 	_HeapTop, 4
+	.lcomm 	_heapbase, 4
 	.lcomm	_atari_4ba_at_prg_start, 4
 	.even
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-sbrk.c b/libgloss/m68k/atari/atari-sbrk.c
index 8839cc742..535395f3e 100644
--- a/libgloss/m68k/atari/atari-sbrk.c
+++ b/libgloss/m68k/atari/atari-sbrk.c
@@ -7,13 +7,25 @@
 #include <_ansi.h>
 
 extern char *_HeapPtr;
-extern char *_HeapBottom;
-extern char *_HeapTop;
+extern char *_heapbase;
 
 char *sbrk(int nbytes)
 {
 	char *newheap = _HeapPtr + nbytes;
-	if (newheap > _HeapTop)
+
+	/*
+		The user stack pointer is the top heap.
+		The behaviour is undefined if we are in supervisor mode.
+		But memory allocations in supervisor mode feels like a bad idea anyway.
+	*/
+	char *heaptop;
+	__asm__ volatile (
+		"move.l	%%a7, %0\n\t"
+		: "=g" (heaptop)
+		:
+		:);
+
+	if (newheap > heaptop)
 	{
 		errno = ENOMEM;
 		return ((char *)-1);
-- 
2.43.0
0003-m68k-atari-elf-updated-readme.patch (text/x-patch, 2.2 KB)
From 71572c4b34caf3c6441812aea615a8048f828f8b Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Fri, 15 Aug 2025 17:31:13 +0200
Subject: [PATCH 3/5] m68k-atari-elf: updated readme

---
 libgloss/m68k/atari/README | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/libgloss/m68k/atari/README b/libgloss/m68k/atari/README
index 24d2a6ea6..20283dd44 100644
--- a/libgloss/m68k/atari/README
+++ b/libgloss/m68k/atari/README
@@ -4,19 +4,19 @@ SPDX-License-Identifier: BSD-2-Clause
 Atari 16/32 bit TOS (not MINT) target.
 Target name: m68k-atari-elf.
 
-Stack size:
-The default stack size is set at 2000 bytes.
-To change stack size, add the following line to your C/C++ code:
-unsigned int _STACK_SIZE = *WANTED_STACK_SIZE*;
-Where "*WANTED_STACK_SIZE*" is the size in bytes you want to allocate for stack space.
-Do not use odd size!
-
-Heap size:
-The default heap size is to use all available memory.
-If you want to leave memory for other programs to use, then add the following line to your C/C++ code:
-unsigned int _HEAP_SIZE = *WANTED_HEAP_SIZE*;
-Where "*WANTED_HEAP_SIZE*" is the size in bytes you want to allocate for heap space.
-Do not use odd size!
+Stack and heap size:
+The symbol: "_stksize" defines how much memory that is reserved for stack and heap using the following scheme:
+1. If "_stksize" is undefined, then all available memory is reserved.
+2. If `int _stksize = SIZE;` is defined anywhere in the code, then "SIZE" is used in this way:
+   * SIZE == 0: then MINKEEP (64KB) memory is reserved.
+   * SIZE == 1: then 1/4 of all memory is reserved.
+   * SIZE == 2: then 2/4 of all memory is reserved.
+   * SIZE == 3: then 3/4 of all memory is reserved.
+   * SIZE >= 4: then SIZE memory is reserved.
+   * SIZE == -1, then all available memory is reserved (for mintlib compatibillity).
+   * SIZE < -1, then -SIZE memory is reserved (for mintlib compatibillity).
+The heap starts at the bottom of the shared memory and the stack starts at the top, and they grow towards eachother.
+A safety check for memory allocations is done to make sure that memory is not allocated and overwriting the stack.
 
 Program base page:
 A pointer to the program base page is stored at: _BasePage
-- 
2.43.0
0004-m68k-atari-elf-proper-setup-of-environment-variables.patch (text/x-patch, 11.9 KB)
From 4a6c2b939efe68b05476fd8002f9c0a5d01295d5 Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Fri, 22 Aug 2025 08:13:39 +0200
Subject: [PATCH 4/5] m68k-atari-elf: proper setup of environment variables and
 program arguments.

---
 libgloss/m68k/atari/atari-crt0.S    |  55 +-----
 libgloss/m68k/atari/atari-crti.S    |  36 +++-
 libgloss/m68k/atari/atari-environ.c | 267 +++++++++++++++++++++++++++-
 3 files changed, 302 insertions(+), 56 deletions(-)

diff --git a/libgloss/m68k/atari/atari-crt0.S b/libgloss/m68k/atari/atari-crt0.S
index 6d1bbd1d9..882be54b0 100644
--- a/libgloss/m68k/atari/atari-crt0.S
+++ b/libgloss/m68k/atari/atari-crt0.S
@@ -4,55 +4,20 @@
 */
 
 	.global exit
+	.global _atari_argv		| in atari-environ.c
+	.global _atari_argc		| in atari-environ.c
 
 	.section	".init"
 	.global	__call_main_with_argc_argv
 	.type	__call_main_with_argc_argv,#function
 __call_main_with_argc_argv:
 
-/*
-	Need to implement "The Atari Extended Argument Specification".
-	Also, there is no guarantee that the command line is zero terminated.
-*/
     | this occurs after crtbegin.o have done all global constructors etc.
-
-	move.l	a7, a6
-	moveq	#0, d0
-	moveq	#0, d2
-	movea.l	_BasePage, a0
-	lea		128(a0), a0		| add offset to the cmdline
-	lea		_cmdline, a1
-	move.b	(a0)+, d2		| d2 contains number of bytes in command line (max 127)
-	beq.s	3f
-	clr.b	(a1, d2.w)		| end our decoded args with a zero.
-	bra.s	2f
-1:
-	move.b	(a0, d2.w), d1
-	cmp.b	#' ', d1
-	bne.s	4f
-	moveq	#0, d1
-	lea		1(a1, d2.w), a2
-	tst.b	(a2)
-	beq.s	4f
-	move.l	a2, -(a7)
-	addq.w	#1, d0
-4:
-	move.b	d1, (a1, d2.w)
-2:
-	subq.w	#1, d2
-	bcc.s	1b
-	move.l	a1, -(a7)
-	addq.w	#1, d0
-3:
-	pea		_procname		| first argument is always the proc name. That we do not know...
-	addq.w	#1, d0
-	move.l	a7, a5
-	move.l	a6, -(a7)		| To know where to move it back again.
-
-	move.l	a5, -(a7)		| argv
-	move.l	d0, -(a7)		| argc
+	| atari-crti.S have already set up _atari_argc, _atari_argv
+	move.l	_atari_argv, -(a7)
+	move.l	_atari_argc, -(a7)
 	jsr		main
-	move.l	8(a7), a7		| move it back.
+	addq.l	#8, a7
 	move.l	d0, -(a7)
 	jsr		exit			| not expected to return
 	illegal
@@ -64,11 +29,3 @@ _exit:
 	move.w	d0, _program_return_code
     | crtend.o follows here with global destructors etc.
 
-	.data
-_procname:
-	.asciz	"yourapp.lol"
-	.even
-
-	.bss
-	.lcomm	_cmdline, 128
-	.even
diff --git a/libgloss/m68k/atari/atari-crti.S b/libgloss/m68k/atari/atari-crti.S
index e11c51cba..caecacef0 100644
--- a/libgloss/m68k/atari/atari-crti.S
+++ b/libgloss/m68k/atari/atari-crti.S
@@ -15,6 +15,7 @@
 	.global _HeapPtr
 	.global _heapbase
 	.global _atari_4ba_at_prg_start
+	.global _atari_4be_at_prg_start
 	.global __BSS_SEGMENT_END
 
 	.section	".init"
@@ -24,6 +25,21 @@ _init:
 	move.l	4(a7),a0
 	move.l	a0, _BasePage
 
+/*
+	First do a quick jump into supervisor mode to get some needed pointers.
+*/
+	move.l	#super_init, -(a7)
+	move.w	#0x26, -(a7)
+	trap	#14
+	addq.l	#6, a7
+
+/*
+	Make an estimate for how much memory we need to reserve for environment and arguments.
+*/
+	jsr		estimate_env_and_args_memory				| in atari-environ.c
+	| d0 contains the number of bytes we need to reserve for environment and arguments.
+	move.l	d0, d7
+	
 /*
 	Init stack and heap.
 	The size of the stack and heap together is specified in _stksize.
@@ -38,11 +54,14 @@ _init:
 		if _stksize < -1, then use -_stksize memory.
 */
 	lea		__BSS_SEGMENT_END, a2
+	add.l	d7, a2			| environment and arguments
 	move.l	a2, _heapbase
 	move.l	a2, _HeapPtr
 
+	move.l	_BasePage, a0
 	move.l	4(a0), d1		| mem top
 	sub.l	a2, d1			| free mem
+	move.l	d1, d6
 	lea		_stksize, a1
 	cmpa.w	#0, a1
 	jeq		stksize_selected
@@ -72,6 +91,13 @@ stksize_above_three:
 	move.l	d0, d1
 stksize_selected:
 
+	| adjust for memory needed for environment and arguments
+	add.l	d7, d1
+	cmp.l	d1, d6
+	jpl		1f
+	move.l	d6, d1
+1:
+
 	add.l	a2, d1
 	bclr	#0, d1		| even address.
 	move.l	d1, a7
@@ -94,12 +120,13 @@ stksize_selected:
 super_init:
 	| Init stuff that needs supervisor mode set.
 	move.l	0x4ba, _atari_4ba_at_prg_start
+	move.l	0x4be, _atari_4be_at_prg_start
 	rts
 heap_setup_done:
-	move.l	#super_init, -(a7)
-	move.w	#0x26, -(a7)
-	trap	#14
-	addq.l	#6, a7
+
+	pea		__BSS_SEGMENT_END				| storage space for environment and arguments
+	jsr		setup_env_and_args				| in atari-environ.c
+
     | crtbegin.o follows here with global constructors etc. init.
 
 
@@ -114,4 +141,5 @@ heap_setup_done:
 	.lcomm 	_HeapPtr, 4
 	.lcomm 	_heapbase, 4
 	.lcomm	_atari_4ba_at_prg_start, 4
+	.lcomm	_atari_4be_at_prg_start, 4
 	.even
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-environ.c b/libgloss/m68k/atari/atari-environ.c
index 3f4970733..5588c2885 100644
--- a/libgloss/m68k/atari/atari-environ.c
+++ b/libgloss/m68k/atari/atari-environ.c
@@ -3,6 +3,267 @@
 	SPDX-License-Identifier: BSD-2-Clause
 */
 
-// Should point to a list of global environment variables.
-char *__env[1] = { 0 };
-char **environ = __env;
\ No newline at end of file
+#include "atari-gem_basepage.h"
+
+/*
+	The functions:
+		void setup_env_and_args(void *mem_ptr)
+		int estimate_env_and_args_memory(void)
+	are called from atari-crti.S and should be handled with care.
+*/
+
+extern char **environ;		// setup_env_and_args will set this up.
+
+// Atari TOS do not supply any method of finding out the name of the application that is running.
+// So we default a name here to have a proper arg1.
+const char _proc_name[] = "_undefin.ed_";
+
+extern const char* _atari_4be_at_prg_start;	// Global environment
+const char **_atari_argv;
+int _atari_argc;
+
+// If storage_list is 0, then vars is only counted.
+// If argv_arg is not 0, then the value of ARGV= is stored there if found.
+int extract_env_vars(const char* env, const char** storage_list, const char** argv_arg)
+{
+	int num = 0;
+	if (env != 0)
+	{
+		// If we find a double null without a previous '=', then the string from the last var
+		// up to the double null must be discarded (aes bug).
+		while (env[0] != 0)		// loop until double null (string beginning with null)
+		{
+			const char* cvar = env;
+			short found_equal = 0;
+			short len_since_equal = 0;
+			while (env[0] != 0)
+			{
+				if (found_equal != 0) {++len_since_equal;}
+				if (env[0] == '=') {found_equal = 1;}
+				++env;
+			}
+			++env;
+			if (found_equal == 0 || len_since_equal == 0)
+			{
+				// This string is not valid, we should ignore it.
+				if (env[0] == 0)
+				{
+					// Double null after invalid string, ignore it.
+					++env;
+				}
+			}
+			else
+			{
+				if (argv_arg != 0 && (env - cvar) > 5 && 
+					(cvar[0] == 'A' && cvar[1] == 'R' && cvar[2] == 'G' && cvar[3] == 'V' && cvar[4] == '='))
+				{
+					*argv_arg = cvar + 5;
+					// We do not count ARGV as it is a part of command line.
+				}
+				else
+				{
+					if (storage_list != 0)
+					{
+						storage_list[num] = cvar;
+					}
+					++num;
+				}
+			}
+		}
+	}
+	return num;
+}
+
+int extract_cmd_args(const char* prg_cmd_line, const char* argv_arg, int* cmd_line_chars, const char** storage_list, char* cmd_line_out)
+{
+	int num = 0;
+	if (storage_list != 0)
+	{
+		storage_list[num] = _proc_name; 
+	}
+	++num;
+
+	int cmd_line_len = ((const unsigned char*)prg_cmd_line)[0];
+	cmd_line_chars[0] = 0;
+	if (cmd_line_len == 0)
+	{
+		return num;
+	}
+	if (cmd_line_len != 127)
+	{
+		// Only use ARGV if length is 127
+		argv_arg = 0;
+	}
+
+	const char* cmdline = prg_cmd_line + 1;
+	char expect = 0;
+	char *arg_start = cmd_line_out;
+	int arglen = 0;
+	while (cmdline != 0)
+	{
+		char c;
+		while ((c = *cmdline++) != 0)
+		{
+			if (c == '\\' && expect == 0)
+			{
+				// Next char will be escaped.
+				expect = '\\';
+			}
+			else if ((c == '\'' || c == '\"') && (expect == c || expect == 0))
+			{
+				// chars between "" or '' should not be escaped nor spaces split into args.
+				expect ^= c;
+			}
+			else if (c == ' ' && expect == 0)
+			{
+				if (arglen != 0)
+				{
+					// found one arg
+					if (cmd_line_out != 0) {*cmd_line_out++ = 0;}
+					cmd_line_chars[0]++;
+					if (storage_list != 0)
+					{
+						storage_list[num] = arg_start; 
+					}
+					++num;
+					arglen = 0;	// Next arg
+					arg_start = cmd_line_out;
+				}
+			}
+			else
+			{
+				if (expect == '\\')
+				{
+					// Only escape one char.
+					expect = 0;
+				}
+				if (cmd_line_out != 0) {*cmd_line_out++ = c;}
+				cmd_line_chars[0]++;
+				++arglen;
+			}
+		}
+
+		// Continue with extended command line if we have one.
+		cmdline = argv_arg;
+		argv_arg = 0;	// To end loop
+	}
+	if (arglen != 0)
+	{
+		if (cmd_line_out != 0) {*cmd_line_out++ = 0;}
+		cmd_line_chars[0]++;
+		if (storage_list != 0)
+		{
+			storage_list[num] = arg_start; 
+		}
+		++num;
+	}
+	return num;
+}
+
+/*
+prg_cmd_line:
+	First byte = length of prg_cmd_line.
+	If length == 127 then "ARGV=" in prg_env contains a string that should be appended to prg_cmd_line.
+prg_env:
+	Contains a set of null terminated strings.
+	Double null ends set.
+global_env:
+	Contains a set of null terminated strings.
+	Double null ends set.
+	AES versions >= 1.4 may multi-args (PATH) with ',', before it was only ';'
+	A bug in AES can cause strings like: "PATH=[nul]A:\[nul][nul]". They should be ignored.
+
+Due to how existing software sets up environment variables on Atari, global_env and prg_env can
+contain duplicates.
+So duplicates will be discarded with prg_env having higher priority than global_env.
+*/
+void setup_env_and_args(void *mem_ptr)
+{
+	/*
+		mem_ptr is guaranteed have the number of bytes reserved that function
+		estimate_env_and_args_memory calculates.
+	*/
+	const char* argv_arg = 0;
+	const char* prg_cmd_line = _BasePage->p_cmdlin;
+	const char* prg_env = _BasePage->p_env;
+	const char* global_env = _atari_4be_at_prg_start;
+
+	// Collect all environment variables.
+	environ = (char**)mem_ptr;
+	int num_env_args = extract_env_vars(prg_env, (const char**)environ, &argv_arg);
+	num_env_args += extract_env_vars(global_env, (const char**)environ, 0);
+	/*
+		Remove duplicates.
+		Not fun as we cannot use any library functions here.
+	*/
+	for (int i = 0; i < num_env_args; ++i)
+	{
+		char* vari = environ[i];
+		if (vari != 0)
+		{
+			for (int j = i + 1; j < num_env_args; ++j)
+			{
+				char* varj = environ[j];
+				if (varj != 0)
+				{
+					char* tvari = vari;
+					while (*tvari == *varj && *tvari != 0 && *tvari != '=')
+					{
+						++tvari;
+						++varj;
+					}
+					if (*tvari == '=' && *varj == '=')
+					{
+						// Found duplicate, clear it with a null pointer.
+						environ[j] = 0;
+					}
+				}
+			}
+		}
+	}
+	// Remove all null variables.
+	int new_num_env_args = 0;
+	for (int i = 0; i < num_env_args; ++i)
+	{
+		if (environ[i] != 0)
+		{
+			environ[new_num_env_args++] = environ[i];
+		}	
+	}
+	environ[new_num_env_args++] = 0;
+
+	// Count command line args
+	int cmd_line_chars = 0;
+	int num_cmd_args = extract_cmd_args(prg_cmd_line, argv_arg, &cmd_line_chars, 0, 0);
+
+	_atari_argv = (const char**)environ + new_num_env_args;
+	char* cmd_line_out = (char*)(_atari_argv + num_cmd_args + 1); 
+	// Collect all command line args.
+	_atari_argc = extract_cmd_args(prg_cmd_line, argv_arg, &cmd_line_chars, _atari_argv, cmd_line_out);
+	_atari_argv[_atari_argc] = 0;
+}
+
+int estimate_env_and_args_memory(void)
+{
+	/*
+		Stack and heap are not properly set up when this function is called.
+		NO memory allocations or large stack usage allowed!
+	*/
+	const char* argv_arg = 0;
+	const char* prg_cmd_line = _BasePage->p_cmdlin;
+	const char* prg_env = _BasePage->p_env;
+	const char* global_env = _atari_4be_at_prg_start;
+
+	int num_env_args = extract_env_vars(prg_env, 0, &argv_arg);
+	num_env_args += extract_env_vars(global_env, 0, 0);
+	int cmd_line_chars = 0;
+	int num_cmd_args = extract_cmd_args(prg_cmd_line, argv_arg, &cmd_line_chars, 0, 0);
+
+	int bytes_to_reserve = (num_env_args + 1) * 4;
+	bytes_to_reserve += (num_cmd_args + 1) * 4;
+	bytes_to_reserve += cmd_line_chars;
+
+	// This is the number of bytes of heap space that will be reserved before
+	// stack and heap is initialized. 
+	return bytes_to_reserve;
+}
\ No newline at end of file
-- 
2.43.0
0005-m68k-atari-elf-specs-file-declares-environ-as-undefi.patch (text/x-patch, 847 B)
From c71bddf39a040492dcfdb27c386227c816b63da4 Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Fri, 26 Sep 2025 08:47:21 +0200
Subject: [PATCH 5/5] m68k-atari-elf: specs file declares environ as undefined.

---
 libgloss/m68k/atari/atari-tos.specs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libgloss/m68k/atari/atari-tos.specs b/libgloss/m68k/atari/atari-tos.specs
index 00781c4fc..02037132c 100644
--- a/libgloss/m68k/atari/atari-tos.specs
+++ b/libgloss/m68k/atari/atari-tos.specs
@@ -4,7 +4,7 @@
 # Atari gcc specs
 
 *link:
-+ --emit-relocs --no-warn-rwx-segments -static --no-warn-execstack --undefined=__errno -T atari-tos.ld
++ --emit-relocs --no-warn-rwx-segments -static --no-warn-execstack --undefined=environ --undefined=__errno -T atari-tos.ld
 
 *lib:
 + -latari-tos
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.