Add new target

<[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <1754337816158.7.107050@webmail-backend-production-957f95bc8-4zxxx>
This adds vendor "atari" for target m68k-elf, resulting in a new possible target: "m68k-atari-elf".

Sorry for spamming the mailinglist earlier. I'm new to this kind of work and didn't read all instructions before previous posts...
0000-cover-letter.patch (text/x-patch, 4.8 KB)
From 7b685033ded7f003b8d45c52da61e8af852726bd Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Mon, 4 Aug 2025 21:52:54 +0200
Subject: [PATCH 0/1] *** SUBJECT HERE ***

*** BLURB HERE ***

Mikael Hildenborg (1):
  Added target m68k-atari-elf supporting Atari 16/32bit TOS systems.

 COPYING.LIBGLOSS                         |   4 +
 COPYING.NEWLIB                           |   4 +
 libgloss/configure                       |  24 +-
 libgloss/configure.ac                    |   5 +
 libgloss/m68k/Makefile.in                |  77 +++++-
 libgloss/m68k/atari/README               |  35 +++
 libgloss/m68k/atari/atari-chdir.c        |  49 ++++
 libgloss/m68k/atari/atari-chown.c        |  20 ++
 libgloss/m68k/atari/atari-close.c        |  23 ++
 libgloss/m68k/atari/atari-crt0.S         |  74 ++++++
 libgloss/m68k/atari/atari-crti.S         |  90 +++++++
 libgloss/m68k/atari/atari-crtn.S         |  24 ++
 libgloss/m68k/atari/atari-environ.c      |   8 +
 libgloss/m68k/atari/atari-execve.c       |  16 ++
 libgloss/m68k/atari/atari-fork.c         |  19 ++
 libgloss/m68k/atari/atari-fstat.c        |  51 ++++
 libgloss/m68k/atari/atari-gem_basepage.h |  58 +++++
 libgloss/m68k/atari/atari-gem_errno.c    |  95 +++++++
 libgloss/m68k/atari/atari-gem_errno.h    |  57 +++++
 libgloss/m68k/atari/atari-getcwd.c       |  32 +++
 libgloss/m68k/atari/atari-getentropy.c   |  52 ++++
 libgloss/m68k/atari/atari-getpid.c       |  11 +
 libgloss/m68k/atari/atari-gettod.c       | 135 ++++++++++
 libgloss/m68k/atari/atari-isatty.c       |  12 +
 libgloss/m68k/atari/atari-kill.c         |  16 ++
 libgloss/m68k/atari/atari-link.c         |  19 ++
 libgloss/m68k/atari/atari-lseek.c        |  43 ++++
 libgloss/m68k/atari/atari-mkdir.c        |  21 ++
 libgloss/m68k/atari/atari-open.c         |  78 ++++++
 libgloss/m68k/atari/atari-read.c         |  44 ++++
 libgloss/m68k/atari/atari-readlink.c     |  20 ++
 libgloss/m68k/atari/atari-rename.c       |  20 ++
 libgloss/m68k/atari/atari-rmdir.c        |  20 ++
 libgloss/m68k/atari/atari-sbrk.c         |  24 ++
 libgloss/m68k/atari/atari-stat.c         |  29 +++
 libgloss/m68k/atari/atari-symlink.c      |  19 ++
 libgloss/m68k/atari/atari-times.c        |  37 +++
 libgloss/m68k/atari/atari-tos.ld         | 160 ++++++++++++
 libgloss/m68k/atari/atari-tos.specs      |  10 +
 libgloss/m68k/atari/atari-traps.c        | 311 +++++++++++++++++++++++
 libgloss/m68k/atari/atari-traps.h        |  84 ++++++
 libgloss/m68k/atari/atari-unlink.c       |  19 ++
 libgloss/m68k/atari/atari-wait.c         |  16 ++
 libgloss/m68k/atari/atari-write.c        |  87 +++++++
 newlib/configure.host                    |   5 +-
 45 files changed, 2043 insertions(+), 14 deletions(-)
 create mode 100644 libgloss/m68k/atari/README
 create mode 100644 libgloss/m68k/atari/atari-chdir.c
 create mode 100644 libgloss/m68k/atari/atari-chown.c
 create mode 100644 libgloss/m68k/atari/atari-close.c
 create mode 100644 libgloss/m68k/atari/atari-crt0.S
 create mode 100644 libgloss/m68k/atari/atari-crti.S
 create mode 100644 libgloss/m68k/atari/atari-crtn.S
 create mode 100644 libgloss/m68k/atari/atari-environ.c
 create mode 100644 libgloss/m68k/atari/atari-execve.c
 create mode 100644 libgloss/m68k/atari/atari-fork.c
 create mode 100644 libgloss/m68k/atari/atari-fstat.c
 create mode 100644 libgloss/m68k/atari/atari-gem_basepage.h
 create mode 100644 libgloss/m68k/atari/atari-gem_errno.c
 create mode 100644 libgloss/m68k/atari/atari-gem_errno.h
 create mode 100644 libgloss/m68k/atari/atari-getcwd.c
 create mode 100644 libgloss/m68k/atari/atari-getentropy.c
 create mode 100644 libgloss/m68k/atari/atari-getpid.c
 create mode 100644 libgloss/m68k/atari/atari-gettod.c
 create mode 100644 libgloss/m68k/atari/atari-isatty.c
 create mode 100644 libgloss/m68k/atari/atari-kill.c
 create mode 100644 libgloss/m68k/atari/atari-link.c
 create mode 100644 libgloss/m68k/atari/atari-lseek.c
 create mode 100644 libgloss/m68k/atari/atari-mkdir.c
 create mode 100644 libgloss/m68k/atari/atari-open.c
 create mode 100644 libgloss/m68k/atari/atari-read.c
 create mode 100644 libgloss/m68k/atari/atari-readlink.c
 create mode 100644 libgloss/m68k/atari/atari-rename.c
 create mode 100644 libgloss/m68k/atari/atari-rmdir.c
 create mode 100644 libgloss/m68k/atari/atari-sbrk.c
 create mode 100644 libgloss/m68k/atari/atari-stat.c
 create mode 100644 libgloss/m68k/atari/atari-symlink.c
 create mode 100644 libgloss/m68k/atari/atari-times.c
 create mode 100644 libgloss/m68k/atari/atari-tos.ld
 create mode 100644 libgloss/m68k/atari/atari-tos.specs
 create mode 100644 libgloss/m68k/atari/atari-traps.c
 create mode 100644 libgloss/m68k/atari/atari-traps.h
 create mode 100644 libgloss/m68k/atari/atari-unlink.c
 create mode 100644 libgloss/m68k/atari/atari-wait.c
 create mode 100644 libgloss/m68k/atari/atari-write.c

-- 
2.43.0
0001-Added-target-m68k-atari-elf-supporting-Atari-16-32bi.patch (text/x-patch, 64.8 KB)
From 7b685033ded7f003b8d45c52da61e8af852726bd Mon Sep 17 00:00:00 2001
From: Mikael Hildenborg <[email protected]>
Date: Mon, 4 Aug 2025 21:50:29 +0200
Subject: [PATCH 1/1] Added target m68k-atari-elf supporting Atari 16/32bit TOS
 systems.

---
 COPYING.LIBGLOSS                         |   4 +
 COPYING.NEWLIB                           |   4 +
 libgloss/configure                       |  24 +-
 libgloss/configure.ac                    |   5 +
 libgloss/m68k/Makefile.in                |  77 +++++-
 libgloss/m68k/atari/README               |  35 +++
 libgloss/m68k/atari/atari-chdir.c        |  49 ++++
 libgloss/m68k/atari/atari-chown.c        |  20 ++
 libgloss/m68k/atari/atari-close.c        |  23 ++
 libgloss/m68k/atari/atari-crt0.S         |  74 ++++++
 libgloss/m68k/atari/atari-crti.S         |  90 +++++++
 libgloss/m68k/atari/atari-crtn.S         |  24 ++
 libgloss/m68k/atari/atari-environ.c      |   8 +
 libgloss/m68k/atari/atari-execve.c       |  16 ++
 libgloss/m68k/atari/atari-fork.c         |  19 ++
 libgloss/m68k/atari/atari-fstat.c        |  51 ++++
 libgloss/m68k/atari/atari-gem_basepage.h |  58 +++++
 libgloss/m68k/atari/atari-gem_errno.c    |  95 +++++++
 libgloss/m68k/atari/atari-gem_errno.h    |  57 +++++
 libgloss/m68k/atari/atari-getcwd.c       |  32 +++
 libgloss/m68k/atari/atari-getentropy.c   |  52 ++++
 libgloss/m68k/atari/atari-getpid.c       |  11 +
 libgloss/m68k/atari/atari-gettod.c       | 135 ++++++++++
 libgloss/m68k/atari/atari-isatty.c       |  12 +
 libgloss/m68k/atari/atari-kill.c         |  16 ++
 libgloss/m68k/atari/atari-link.c         |  19 ++
 libgloss/m68k/atari/atari-lseek.c        |  43 ++++
 libgloss/m68k/atari/atari-mkdir.c        |  21 ++
 libgloss/m68k/atari/atari-open.c         |  78 ++++++
 libgloss/m68k/atari/atari-read.c         |  44 ++++
 libgloss/m68k/atari/atari-readlink.c     |  20 ++
 libgloss/m68k/atari/atari-rename.c       |  20 ++
 libgloss/m68k/atari/atari-rmdir.c        |  20 ++
 libgloss/m68k/atari/atari-sbrk.c         |  24 ++
 libgloss/m68k/atari/atari-stat.c         |  29 +++
 libgloss/m68k/atari/atari-symlink.c      |  19 ++
 libgloss/m68k/atari/atari-times.c        |  37 +++
 libgloss/m68k/atari/atari-tos.ld         | 160 ++++++++++++
 libgloss/m68k/atari/atari-tos.specs      |  10 +
 libgloss/m68k/atari/atari-traps.c        | 311 +++++++++++++++++++++++
 libgloss/m68k/atari/atari-traps.h        |  84 ++++++
 libgloss/m68k/atari/atari-unlink.c       |  19 ++
 libgloss/m68k/atari/atari-wait.c         |  16 ++
 libgloss/m68k/atari/atari-write.c        |  87 +++++++
 newlib/configure.host                    |   5 +-
 45 files changed, 2043 insertions(+), 14 deletions(-)
 create mode 100644 libgloss/m68k/atari/README
 create mode 100644 libgloss/m68k/atari/atari-chdir.c
 create mode 100644 libgloss/m68k/atari/atari-chown.c
 create mode 100644 libgloss/m68k/atari/atari-close.c
 create mode 100644 libgloss/m68k/atari/atari-crt0.S
 create mode 100644 libgloss/m68k/atari/atari-crti.S
 create mode 100644 libgloss/m68k/atari/atari-crtn.S
 create mode 100644 libgloss/m68k/atari/atari-environ.c
 create mode 100644 libgloss/m68k/atari/atari-execve.c
 create mode 100644 libgloss/m68k/atari/atari-fork.c
 create mode 100644 libgloss/m68k/atari/atari-fstat.c
 create mode 100644 libgloss/m68k/atari/atari-gem_basepage.h
 create mode 100644 libgloss/m68k/atari/atari-gem_errno.c
 create mode 100644 libgloss/m68k/atari/atari-gem_errno.h
 create mode 100644 libgloss/m68k/atari/atari-getcwd.c
 create mode 100644 libgloss/m68k/atari/atari-getentropy.c
 create mode 100644 libgloss/m68k/atari/atari-getpid.c
 create mode 100644 libgloss/m68k/atari/atari-gettod.c
 create mode 100644 libgloss/m68k/atari/atari-isatty.c
 create mode 100644 libgloss/m68k/atari/atari-kill.c
 create mode 100644 libgloss/m68k/atari/atari-link.c
 create mode 100644 libgloss/m68k/atari/atari-lseek.c
 create mode 100644 libgloss/m68k/atari/atari-mkdir.c
 create mode 100644 libgloss/m68k/atari/atari-open.c
 create mode 100644 libgloss/m68k/atari/atari-read.c
 create mode 100644 libgloss/m68k/atari/atari-readlink.c
 create mode 100644 libgloss/m68k/atari/atari-rename.c
 create mode 100644 libgloss/m68k/atari/atari-rmdir.c
 create mode 100644 libgloss/m68k/atari/atari-sbrk.c
 create mode 100644 libgloss/m68k/atari/atari-stat.c
 create mode 100644 libgloss/m68k/atari/atari-symlink.c
 create mode 100644 libgloss/m68k/atari/atari-times.c
 create mode 100644 libgloss/m68k/atari/atari-tos.ld
 create mode 100644 libgloss/m68k/atari/atari-tos.specs
 create mode 100644 libgloss/m68k/atari/atari-traps.c
 create mode 100644 libgloss/m68k/atari/atari-traps.h
 create mode 100644 libgloss/m68k/atari/atari-unlink.c
 create mode 100644 libgloss/m68k/atari/atari-wait.c
 create mode 100644 libgloss/m68k/atari/atari-write.c

diff --git a/COPYING.LIBGLOSS b/COPYING.LIBGLOSS
index 7eed3ab29..7dbcbfec1 100644
--- a/COPYING.LIBGLOSS
+++ b/COPYING.LIBGLOSS
@@ -497,3 +497,7 @@ and need not follow the licensing terms described here, provided that
 the new terms are clearly indicated on the first page of each file where
 they apply.
 
+(26) - Atari 16/32 bit TOS (m68k-atari-elf target)
+
+Copyright (C) 2025 Mikael Hildenborg
+SPDX-License-Identifier: BSD-2-Clause
diff --git a/COPYING.NEWLIB b/COPYING.NEWLIB
index 9a2680d09..2bf6f0bed 100644
--- a/COPYING.NEWLIB
+++ b/COPYING.NEWLIB
@@ -1570,3 +1570,7 @@ Software.
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+(58) - Atari 16/32 bit TOS (m68k-atari-elf target)
+
+Copyright (C) 2025 Mikael Hildenborg
+SPDX-License-Identifier: BSD-2-Clause
diff --git a/libgloss/configure b/libgloss/configure
index 3eb4c2740..369780c64 100755
--- a/libgloss/configure
+++ b/libgloss/configure
@@ -2857,6 +2857,11 @@ case "${target}" in
 	ac_config_files="$ac_config_files m68k/Makefile"
 
 	subdirs="$subdirs m68k"
+	case "${target}" in
+		m68k-atari-*)
+			config_libnosys=false
+		;;
+	esac
 	;;
   hppa*-*-pro*)
 	ac_config_files="$ac_config_files pa/Makefile"
@@ -5461,16 +5466,18 @@ case "${target}" in
     MIPS_SCRIPT_LIST="dve idt jmr3904app jmr3904dram jmr3904dram-java jmr3904app-java sde32 sde64 mti32 mti64 mti64_n32 mti64_64"
     MIPS_BSP_LIST="libdve.a libidt.a libjmr3904.a"
     ;;
+  mipsisa32-*-* | mipsisa32el-*-* | \
+  mipsisa32r2-*-* | mipsisa32r2el-*-* | \
+  mipsisa64*-*-*)
+    MIPS_CRT0="crt0_cfe.o crt0_cygmon.o crt0.o"
+    MIPS_SCRIPT_LIST="idt32 idt64 cfe"
+    MIPS_BSP_LIST="libcygmon.a libidt.a libcfe.a"
+    ;;
   mips*-lsi*-*)
     MIPS_PART_SPECIFIC_OBJ="entry.o"
     MIPS_SCRIPT_LIST="lsi"
     MIPS_BSP_LIST=liblsi.a
     ;;
-  mips*-mti*-* | mips*-img*-*)
-    MIPS_CRT0="crt0.o"
-    MIPS_SCRIPT_LIST="idt nullmon mti32 mti64_n32 mti64_64 uhi32 uhi64_64 uhi64_n32 malta32-yamon bootcode"
-    MIPS_BSP_LIST="libidt.a libnullmon.a libuhi.a libyamon.a libhal.a libcm3_impl.a"
-    ;;
   mips64vr5*-*-*)
     MIPS_PART_SPECIFIC_OBJ="vr5xxx.o cma101.o"
     MIPS_PART_SPECIFIC_DEFINES=-DR5000
@@ -5482,13 +5489,6 @@ case "${target}" in
     MIPS_SCRIPT_LIST="ddb ddb-kseg0 nullmon"
     MIPS_BSP_LIST="libpmon.a libnullmon.a"
     ;;
-  mipsisa32-*-* | mipsisa32el-*-* | \
-  mipsisa32r2-*-* | mipsisa32r2el-*-* | \
-  mipsisa64*-*-*)
-    MIPS_CRT0="crt0_cfe.o crt0_cygmon.o crt0.o"
-    MIPS_SCRIPT_LIST="idt32 idt64 cfe"
-    MIPS_BSP_LIST="libcygmon.a libidt.a libcfe.a"
-    ;;
   mips*)
     MIPS_CRT0="crt0_cfe.o crt0.o"
     MIPS_PART_SPECIFIC_OBJ="vr4300.o cma101.o"
diff --git a/libgloss/configure.ac b/libgloss/configure.ac
index 628f173d6..0ab0cc248 100644
--- a/libgloss/configure.ac
+++ b/libgloss/configure.ac
@@ -79,6 +79,11 @@ case "${target}" in
   fido-*-* | m68*-*-*)
 	AC_CONFIG_FILES([m68k/Makefile])
 	subdirs="$subdirs m68k"
+	case "${target}" in
+		m68k-atari-*)
+			config_libnosys=false
+		;;
+	esac
 	;;
   hppa*-*-pro*)
 	AC_CONFIG_FILES([pa/Makefile])
diff --git a/libgloss/m68k/Makefile.in b/libgloss/m68k/Makefile.in
index 7f67426a6..b6d1868bc 100644
--- a/libgloss/m68k/Makefile.in
+++ b/libgloss/m68k/Makefile.in
@@ -31,6 +31,7 @@ program_transform_name = @program_transform_name@
 bindir = @bindir@
 libdir = @libdir@
 tooldir = $(exec_prefix)/$(target_alias)
+specsdir = $(libdir)/gcc/$(target_alias)
 
 # Multilib support variables.
 # TOP is used instead of MULTI{BUILD,SRC}TOP.
@@ -71,6 +72,14 @@ OBJS =  close.o fstat.o getpid.o isatty.o kill.o \
 # What targets to build for.  This is a list of {m68k,cf}
 TARGET = @M68K_TARGET@
 
+# Check if vendor is atari and if so, adjust the target
+target_vendor = @target_vendor@
+ifdef target_vendor
+	ifeq ($(target_vendor), atari)
+		TARGET := $(TARGET)_$(target_vendor)
+	endif
+endif
+
 # Here is all of the simulator stuff
 SIM_SCRIPTS	= sim.ld
 SIM_LDFLAGS	= -Tsim.ld
@@ -197,6 +206,29 @@ UNHOSTED_OBJS=	unhosted-close.o unhosted-fstat.o \
 HOSTED_BSP=	libhosted.a
 HOSTED_OBJS=	hosted-gdb.o hosted-exit.o $(patsubst un%,%,$(UNHOSTED_OBJS))
 
+#
+# here's all the atari stuff
+#
+
+ATARI_SRC_LIBGLOSS := atari-environ.c atari-execve.c atari-link.c atari-times.c \
+	atari-wait.c atari-traps.c atari-gem_errno.c atari-close.c atari-fstat.c \
+	atari-getpid.c atari-isatty.c atari-kill.c atari-lseek.c atari-open.c atari-read.c \
+	atari-sbrk.c atari-stat.c atari-unlink.c atari-write.c \
+	atari-chown.c atari-fork.c atari-getentropy.c atari-gettod.c atari-readlink.c \
+	atari-symlink.c atari-chdir.c atari-getcwd.c atari-mkdir.c atari-rmdir.c \
+	atari-rename.c
+
+ATARI_OBJS_LIBGLOSS := $(foreach source,$(ATARI_SRC_LIBGLOSS),$(basename $(source)).o)
+
+ATARI_CRTI := atari-crti.o
+ATARI_CRTN := atari-crtn.o
+ATARI_CRT0 := atari-crt0.o
+ATARI_NEWLIB := libatari-tos.a
+ATARI_LINK := atari-tos.ld
+ATARI_SPECS := atari-tos.specs
+
+ATARI_ASFLAGS := -Xassembler --register-prefix-optional
+
 # Host specific makefile fragment comes in here.
 @host_makefile_frag@
 
@@ -206,9 +238,19 @@ all :: $(TARGET:%=all_%)
 # here's where we build the board support packages for each target
 #
 
+.PHONY: all_m68k_atari
+all_m68k_atari :: $(ATARI_CRTI) $(ATARI_CRTN) $(ATARI_CRT0) $(ATARI_NEWLIB)
+
+.PHONY: all_cf_atari
+all_cf_atari :: all_m68k_atari
+
+.PHONY: all_fido_atari
+all_fido_atari :: all_m68k_atari
+
 .PHONY: all_m68k
 all_m68k :: ${SIM_CRT0} ${SIM_BSP} ${CRT0} ${BCC_BSP} ${IDP_BSP} \
 	${IDPGDB_BSP} ${MVME135_BSP} ${MVME162_BSP}
+
 .PHONY: all_cf
 all_cf :: ${CF_CRT0S} ${CF_BSP} ${CF_SCRIPTS} ${HOSTED_BSP} ${UNHOSTED_BSP}
 
@@ -240,6 +282,23 @@ ${MVME162_BSP}: $(OBJS) ${MVME162_OBJS}
 	${AR} ${ARFLAGS} $@ $(OBJS) ${MVME162_OBJS}
 	${RANLIB} $@
 
+# build atari library
+$(ATARI_CRT0): atari/atari-crt0.S
+	$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(ATARI_ASFLAGS) -c $< -o $@
+
+$(ATARI_CRTI): atari/atari-crti.S
+	$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(ATARI_ASFLAGS) -c $< -o $@
+
+$(ATARI_CRTN): atari/atari-crtn.S
+	$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(ATARI_ASFLAGS) -c $< -o $@
+
+%.o: atari/%.c
+	$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+$(ATARI_NEWLIB): $(ATARI_OBJS_LIBGLOSS)
+	$(AR) $(ARFLAGS) $@ $^
+	$(RANLIB) $@
+
 # build hosted library
 $(HOSTED_OBJS): hosted%.o: io%.c io.h
 	$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) -DHOSTED=1 $(INCLUDES) -c $< -o $@
@@ -409,6 +468,22 @@ unlink.o: $(srcdir)/../unlink.c
 install:: $(TARGET:%=install_%)
 
 
+.PHONY:install_m68k_atari
+install_m68k_atari::
+	${mkinstalldirs} ${DESTDIR}${tooldir}/lib${MULTISUBDIR}
+	$(INSTALL_PROGRAM) $(ATARI_CRTI) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/crti.o
+	$(INSTALL_PROGRAM) $(ATARI_CRTN) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/crtn.o
+	$(INSTALL_PROGRAM) $(ATARI_CRT0) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/crt0.o
+	$(INSTALL_PROGRAM) $(ATARI_NEWLIB) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/$(ATARI_NEWLIB)
+	$(INSTALL_DATA) ${srcdir}/atari/$(ATARI_LINK) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/$(ATARI_LINK)
+	$(INSTALL_DATA) ${srcdir}/atari/$(ATARI_SPECS) $(DESTDIR)$(specsdir)/specs
+
+.PHONY:install_cf_atari
+install_cf_atari:: install_m68k_atari
+
+.PHONY:install_fido_atari
+install_fido_atari:: install_m68k_atari
+
 .PHONY:install_m68k
 install_m68k::
 	${mkinstalldirs} ${DESTDIR}${tooldir}/lib${MULTISUBDIR}
@@ -473,7 +548,7 @@ install_io::
 @target_makefile_frag@
 
 clean mostlyclean:
-	rm -f a.out core *.i *~ *.a *.o *-test *.srec *.dis *.x *.map
+	rm -f a.out core *.i *~ *.a *.o *-test *.srec *.dis *.x *.map *.ld
 
 distclean maintainer-clean realclean: clean
 	rm -f Makefile
diff --git a/libgloss/m68k/atari/README b/libgloss/m68k/atari/README
new file mode 100644
index 000000000..24d2a6ea6
--- /dev/null
+++ b/libgloss/m68k/atari/README
@@ -0,0 +1,35 @@
+Copyright (C) 2025 Mikael Hildenborg
+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!
+
+Program base page:
+A pointer to the program base page is stored at: _BasePage
+
+ELF output:
+The executable elf output have four interesting segments:
+".text", ".data", ".bss" and ".prgheader" as described in "atari-tos.ld".
+All relevant code and data have been properly sorted into those segments, and the ".prgheader"
+contains a valid atari prg header pointing to relevant segments.
+Relocation data from the link switch "--emit-relocs" (defaultted by "atari-tos.specs") is
+included in the elf output so additional fixup information can be added to the prg file.
+Addresses in elf and prg files are the same and thus compatible for interchangeable symbol lookup.
+
+More information:
+Can be found at: https://github.com/hildenborg/m68k-atari-dev
+Where build scripts for complete toolchain, executables for converting elf to prg, and a remote debug server with full symbolic debugging are available.
diff --git a/libgloss/m68k/atari/atari-chdir.c b/libgloss/m68k/atari/atari-chdir.c
new file mode 100644
index 000000000..edb7a70d8
--- /dev/null
+++ b/libgloss/m68k/atari/atari-chdir.c
@@ -0,0 +1,49 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+int chdir(const char *path)
+{
+	int err = GEM_E_OK;
+	if (path != 0)
+	{
+		if (path[1] == ':')
+		{
+			unsigned int drives = 0;
+			unsigned short drive = 0;
+			if (path[0] >= 'A' && path[0] <= 'Z')
+			{
+				drive = (unsigned short)(path[0] - 'A');
+			}
+			else if (path[0] >= 'a' && path[0] <= 'z')
+			{
+				drive = (unsigned short)(path[0] - 'a');
+			}
+			drives = trap1_e(drive);
+			if ((drives & (1 << drive)) == 0)
+			{
+				err = GEM_EDRIVE;
+			}
+			path += 2;
+		}
+		if (err == GEM_E_OK)
+		{
+			err = trap1_3b(path);
+		}
+	}
+	else
+	{
+		err = GEM_EPTHNF;
+	}
+	if (err < 0)
+	{
+		gem_error_to_errno(err);
+		return -1;
+	}
+	return 0;
+}
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-chown.c b/libgloss/m68k/atari/atari-chown.c
new file mode 100644
index 000000000..62f830002
--- /dev/null
+++ b/libgloss/m68k/atari/atari-chown.c
@@ -0,0 +1,20 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <_syslist.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include "libnosys/warning.h"
+
+int chown(const char *path, uid_t owner, gid_t group)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+stub_warning(chown)
diff --git a/libgloss/m68k/atari/atari-close.c b/libgloss/m68k/atari/atari-close.c
new file mode 100644
index 000000000..a52049c1d
--- /dev/null
+++ b/libgloss/m68k/atari/atari-close.c
@@ -0,0 +1,23 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+int close(int fd)
+{
+	int err = GEM_EIHNDL;
+	if (fd >= 0)
+	{
+		err = trap1_3e((unsigned short)fd);
+	}
+	if (err <  0)
+	{
+		gem_error_to_errno(err);
+		return -1;
+	}
+	return 0;
+}
diff --git a/libgloss/m68k/atari/atari-crt0.S b/libgloss/m68k/atari/atari-crt0.S
new file mode 100644
index 000000000..6d1bbd1d9
--- /dev/null
+++ b/libgloss/m68k/atari/atari-crt0.S
@@ -0,0 +1,74 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+	.global exit
+
+	.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
+	jsr		main
+	move.l	8(a7), a7		| move it back.
+	move.l	d0, -(a7)
+	jsr		exit			| not expected to return
+	illegal
+
+	.global _exit
+	.type	_exit,#function
+_exit:
+	move.l 4(a7), d0
+	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
new file mode 100644
index 000000000..5e4c13b0e
--- /dev/null
+++ b/libgloss/m68k/atari/atari-crti.S
@@ -0,0 +1,90 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#ifdef _HAVE_INITFINI_ARRAY
+#define _init	__libc_init_array
+#define _fini	__libc_fini_array
+#endif
+
+	.equ	DEFAULT_STACK, 2000
+
+	.global _BasePage
+	.weak 	_STACK_SIZE
+	.weak 	_HEAP_SIZE
+	.global _HeapPtr
+	.global _HeapBottom
+	.global _HeapTop
+	.global _atari_4ba_at_prg_start
+	.global __BSS_SEGMENT_END
+
+	.section	".init"
+	.global	_init
+	.type	_init,#function
+_init:
+	move.l	4(a7),a0
+	move.l	a0, _BasePage
+
+	| Init stack
+	lea		__BSS_SEGMENT_END, a2
+	lea		_STACK_SIZE, 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
+
+	| Init heap
+	move.l	a7, d0
+	move.l	d0, _HeapBottom
+	move.l	d0, _HeapPtr
+	move.l	4(a0), _HeapTop
+
+	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
+
+	| Program do not want all memory, so we shrink it.
+	move.l	d0, -(a7)
+	move.l	a0, -(a7)
+	clr.w	-(a7)
+	move.w	#0x4a, -(a7)	| Mshrink()
+	trap	#1
+	lea		12(a7), a7
+	tst.l	d0
+	jpl		heap_setup_done
+    | Error, just quit with d0 as return code.
+	move.w	d0,-(a7)
+	move.w	#0x4c,-(a7)
+	trap	#1
+super_init:
+	| Init stuff that needs supervisor mode set.
+	move.l	0x4ba, _atari_4ba_at_prg_start
+	rts
+heap_setup_done:
+	move.l	#super_init, -(a7)
+	move.w	#0x26, -(a7)
+	trap	#14
+	addq.l	#6, a7
+    | crtbegin.o follows here with global constructors etc. init.
+
+
+	.section	".fini"
+	/*
+		Empty.
+	*/
+
+
+	.bss
+	.lcomm 	_BasePage, 4
+	.lcomm 	_HeapPtr, 4
+	.lcomm 	_HeapBottom, 4
+	.lcomm 	_HeapTop, 4
+	.lcomm	_atari_4ba_at_prg_start, 4
+	.even
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-crtn.S b/libgloss/m68k/atari/atari-crtn.S
new file mode 100644
index 000000000..6482a9c9f
--- /dev/null
+++ b/libgloss/m68k/atari/atari-crtn.S
@@ -0,0 +1,24 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+    .global _program_return_code
+
+	.section	".init"
+	/*
+		Empty.
+	*/
+
+
+	.section	".fini"
+	.global	_fini
+	.type	_fini,#function
+_fini:
+    | this occurs after crtend.o have done all global destructors etc.
+	move.w	_program_return_code,-(a7)
+	move.w	#0x4c,-(a7)
+	trap	#1
+
+	.bss
+    .lcomm  _program_return_code, 2
diff --git a/libgloss/m68k/atari/atari-environ.c b/libgloss/m68k/atari/atari-environ.c
new file mode 100644
index 000000000..3f4970733
--- /dev/null
+++ b/libgloss/m68k/atari/atari-environ.c
@@ -0,0 +1,8 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	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
diff --git a/libgloss/m68k/atari/atari-execve.c b/libgloss/m68k/atari/atari-execve.c
new file mode 100644
index 000000000..c7a572154
--- /dev/null
+++ b/libgloss/m68k/atari/atari-execve.c
@@ -0,0 +1,16 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <errno.h>
+#include "libnosys/warning.h"
+
+int execve(char *name, char **argv, char **env)
+{
+    errno = ENOSYS;
+	return -1;
+}
+
+stub_warning(execve)
diff --git a/libgloss/m68k/atari/atari-fork.c b/libgloss/m68k/atari/atari-fork.c
new file mode 100644
index 000000000..e16436fbf
--- /dev/null
+++ b/libgloss/m68k/atari/atari-fork.c
@@ -0,0 +1,19 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <_syslist.h>
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include "libnosys/warning.h"
+
+int fork(void)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+stub_warning(fork)
diff --git a/libgloss/m68k/atari/atari-fstat.c b/libgloss/m68k/atari/atari-fstat.c
new file mode 100644
index 000000000..a48a00930
--- /dev/null
+++ b/libgloss/m68k/atari/atari-fstat.c
@@ -0,0 +1,51 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <sys/stat.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+#include "atari-gem_basepage.h"
+
+/*
+	From man page:
+	"only the st_uid, st_gid, st_size, and st_mode fields,
+	and only the S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH file permission bits need be valid."
+*/
+
+int fstat(int fd, struct stat *buf)
+{
+	struct DTA *dta = (struct DTA *)GEM_EIHNDL;
+	// For now, we just support files.
+	if (fd >= 6)
+	{
+		buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
+		// files
+		dta = trap1_2f((unsigned int)fd);
+		if ((int)dta >= 0)
+		{
+			// Attribs
+			buf->st_mode |= (dta->d_attrib & FA_DIR) ? S_IFDIR : S_IFREG;
+			if ((dta->d_attrib & FA_READONLY) != 0)
+			{
+				buf->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+			}
+			buf->st_size = dta->d_length;
+			// st_uid, st_gid have no meaning for the st, so we ignore them.
+		}
+	}
+	else
+	{
+		// unsupported, fake something.
+		buf->st_mode = S_IFCHR;
+		buf->st_blksize = 0;
+	}
+	if ((int)dta < 0)
+	{
+		gem_error_to_errno((int)dta);
+		return -1;
+	}
+	return 0;
+}
diff --git a/libgloss/m68k/atari/atari-gem_basepage.h b/libgloss/m68k/atari/atari-gem_basepage.h
new file mode 100644
index 000000000..461c3ce9b
--- /dev/null
+++ b/libgloss/m68k/atari/atari-gem_basepage.h
@@ -0,0 +1,58 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#ifndef GEM_BASEPAGE_H
+#define GEM_BASEPAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+	This is the process base page data, containing information about the executable.
+*/
+
+#define FA_READONLY	0x01	// Read-only flag
+#define FA_HIDDEN 0x02		// Hidden file flag
+#define FA_SYSTEM 0x04		// System file flag
+#define FA_VOLUME 0x08		// Volume label flag
+#define FA_DIR 0x10			// Subdirectory
+#define FA_ARCHIVE 0x20		// Archive flag
+
+struct DTA
+{
+	unsigned char d_reserved[21];
+	unsigned char d_attrib;
+	unsigned short d_time;
+	unsigned short d_date;
+	unsigned int d_length;
+	char d_fname[14];
+};
+
+struct BasePage
+{
+	unsigned char* p_lowtpa;	// This LONG contains a pointer to the Transient Program Area (TPA).
+	unsigned char* p_hitpa;		// This LONG contains a pointer to the top of the TPA + 1.
+	unsigned char* p_tbase;		// This LONG contains a pointer to the base of the text segment
+	unsigned int p_tlen;		// This LONG contains the length of the text segment.
+	unsigned char* p_dbase;		// This LONG contains a pointer to the base of the data segment.
+	unsigned int p_dlen;		// This LONG contains the length of the data segment.
+	unsigned char* p_bbase;		// This LONG contains a pointer to the base of the BSS segment.
+	unsigned int p_blen;		// This LONG contains the length of the BSS segment.
+	struct DTA* p_dta;			// This LONG contains a pointer to the processes’ DTA.
+	struct BasePage* p_parent;	// This LONG contains a pointer to the processes’ parent’s basepage.
+	unsigned int p_reserved;	// This LONG is currently unused and is reserved.
+	char* p_env;				// This LONG contains a pointer to the processes’ environment string.
+	unsigned char p_undef[80];	// This area contains 80 unused, reserved bytes.
+	char p_cmdlin[128];			// This area contains a copy of the 128 byte command line string.
+};
+
+extern struct BasePage* _BasePage;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GEM_BASEPAGE_H
diff --git a/libgloss/m68k/atari/atari-gem_errno.c b/libgloss/m68k/atari/atari-gem_errno.c
new file mode 100644
index 000000000..641a0b212
--- /dev/null
+++ b/libgloss/m68k/atari/atari-gem_errno.c
@@ -0,0 +1,95 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include <_ansi.h>
+
+/*
+	The conversion between gem errors and errno is not a one to one match,
+	so the goal has been to try and report errors to errno in such way that
+	code depending on this will run as expected.
+	This remains to be proven correct.
+*/
+void gem_error_to_errno(int gem_error)
+{
+	errno = ENOSYS; // Use this as default error code.
+	switch (gem_error)
+	{
+	case GEM_EDRVNR:
+	case GEM_EMEDIA:
+	case GEM_EPAPER:
+		errno = EIO;
+		break;
+	case GEM_EBADRQ:
+		errno = EINVAL;
+		break;
+	case GEM_E_SEEK:
+		errno = ESPIPE;
+		break;
+	case GEM_ESECNF:
+	case GEM_EWRITF:
+	case GEM_EREADF:
+		errno = EIO;
+		break;
+	case GEM_EWRPRO:
+		errno = EROFS;
+		break;
+	case GEM_EUNDEV:
+	case GEM_EDRIVE:
+		errno = ENODEV;
+		break;
+	case GEM_EFILNF:
+	case GEM_EPTHNF:
+	case GEM_EMOUNT:
+		errno = ENOENT;
+		break;
+	case GEM_ENHNDL:
+	case GEM_ENMFIL:
+		errno = EMFILE;
+		break;
+	case GEM_EACCDN:
+		errno = EACCES;
+		break;
+	case GEM_EIHNDL:
+		errno = EBADF;
+		break;
+	case GEM_ENSMEM:
+	case GEM_EGSBF:
+		errno = ENOMEM;
+		break;
+	case GEM_EIMBA:
+		errno = EADDRNOTAVAIL;
+		break;
+	case GEM_ENSAME:
+		errno = EXDEV;
+		break;
+	case GEM_ELOCKED:
+	case GEM_ENSLOCK:
+		errno = ENOLCK;
+		break;
+	case GEM_ENAMETOOLONG:
+		errno = ENAMETOOLONG;
+		break;
+	case GEM_EPLFMT:
+		errno = ENOEXEC;
+		break;
+	case GEM_ELOOP:
+		errno = EMLINK;
+		break;
+	case GEM_E_OK:
+	case GEM_ERROR:
+	case GEM_EUNCMD:
+	case GEM_E_CRC:
+	case GEM_E_CHNG:
+	case GEM_EBADSF:
+	case GEM_EOTHER:
+	case GEM_EINVFN:
+	case GEM_EINTRN:
+	default:
+		errno = -gem_error;
+		break;
+	}
+}
diff --git a/libgloss/m68k/atari/atari-gem_errno.h b/libgloss/m68k/atari/atari-gem_errno.h
new file mode 100644
index 000000000..c61478dba
--- /dev/null
+++ b/libgloss/m68k/atari/atari-gem_errno.h
@@ -0,0 +1,57 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#ifndef GEM_ERRNO_DEFINED
+#define GEM_ERRNO_DEFINED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GEM_E_OK 			0		// No error
+#define GEM_ERROR 			-1		// Generic error
+#define GEM_EDRVNR 			-2		// Drive not ready
+#define GEM_EUNCMD 			-3		// Unknown command
+#define GEM_E_CRC 			-4		// CRC error
+#define GEM_EBADRQ			-5		// Bad request
+#define GEM_E_SEEK			-6		// Seek error
+#define GEM_EMEDIA			-7		// Unknown media
+#define GEM_ESECNF			-8		// Sector not found
+#define GEM_EPAPER			-9		// Out of paper
+#define GEM_EWRITF			-10		// Write fault
+#define GEM_EREADF			-11		// Read fault
+#define GEM_EWRPRO			-12		// Device is write protected
+#define GEM_E_CHNG			-14		// Media change detected
+#define GEM_EUNDEV			-15		// Unknown device
+#define GEM_EBADSF			-16		// Bad sectors on format
+#define GEM_EOTHER			-17		// Insert other disk (request)
+#define GEM_EINVFN			-32		// Invalid function
+#define GEM_EFILNF			-33		// File not found
+#define GEM_EPTHNF			-34		// Path not found
+#define GEM_ENHNDL			-35		// No more handles
+#define GEM_EACCDN			-36		// Access denied
+#define GEM_EIHNDL			-37		// Invalid handle
+#define GEM_ENSMEM			-39		// Insufficient memory
+#define GEM_EIMBA 			-40		// Invalid memory block address
+#define GEM_EDRIVE			-46		// Invalid drive specification
+#define GEM_ENSAME			-48		// Cross device rename
+#define GEM_ENMFIL			-49		// No more files
+#define GEM_ELOCKED			-58		// Record is already locked
+#define GEM_ENSLOCK			-59		// Invalid lock removal request
+#define GEM_ERANGE			-64		// Range error
+#define GEM_ENAMETOOLONG	-64		// Range error
+#define GEM_EINTRN			-65		// Internal error
+#define GEM_EPLFMT			-66		// Invalid program load format
+#define GEM_EGSBF			-67		// Memory block growth failure
+#define GEM_ELOOP			-80		// Too many symbolic links
+#define GEM_EMOUNT			-200	// Mount point crossed (indicator)
+
+void gem_error_to_errno(int gem_error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GEM_ERRNO_DEFINED
diff --git a/libgloss/m68k/atari/atari-getcwd.c b/libgloss/m68k/atari/atari-getcwd.c
new file mode 100644
index 000000000..37d778e42
--- /dev/null
+++ b/libgloss/m68k/atari/atari-getcwd.c
@@ -0,0 +1,32 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+char *getcwd(char *buf, size_t size)
+{
+	char *retbuf = buf;
+	if (retbuf == 0)
+	{
+		errno = EIO;
+		return 0;
+	}
+
+	unsigned short drive = trap1_19();
+	int result = trap1_47(retbuf + 2, drive + 1);
+	if (result < 0)
+	{
+		gem_error_to_errno(result);
+		return 0;
+	}
+	retbuf[0] = (char)('A' + drive);
+	retbuf[1] = ':';
+	return retbuf;
+}
diff --git a/libgloss/m68k/atari/atari-getentropy.c b/libgloss/m68k/atari/atari-getentropy.c
new file mode 100644
index 000000000..0b5b461b9
--- /dev/null
+++ b/libgloss/m68k/atari/atari-getentropy.c
@@ -0,0 +1,52 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <_ansi.h>
+#include <_syslist.h>
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+/*
+    Xorshift pseudorandom number generator.
+    https://en.wikipedia.org/wiki/Xorshift
+    Inited with random seed.
+*/
+
+int getentropy(void *buf, size_t buflen)
+{
+    unsigned int a;
+    unsigned int state[4];
+
+    // Init state
+    a = trap14_11();     // Atari Random func.
+    for (int i = 0; i < 4; ++i)
+    {
+        // xorshift32
+        a ^= (a << 13);
+        a ^= (a >> 17);
+        a ^= (a << 5);
+        state[i] = a;
+    }
+
+    for (size_t i = 0; i < buflen; ++i)
+    {
+        // xorshift128
+        unsigned int t = state[3];
+        unsigned int s = state[0];
+        state[3] = state[2];
+        state[2] = state[1];
+        state[1] = s;
+
+        t ^= t << 11;
+        t ^= t >> 7;
+        state[0] = t ^ s ^ (s >> 19);
+
+        // use lowest byte (could be optimized to adapt to buf len and output whole 32 bits when possible.)
+        ((unsigned char*)buf)[i] = (unsigned char)state[0];
+    }
+
+    return 0;
+}
diff --git a/libgloss/m68k/atari/atari-getpid.c b/libgloss/m68k/atari/atari-getpid.c
new file mode 100644
index 000000000..98e001eb9
--- /dev/null
+++ b/libgloss/m68k/atari/atari-getpid.c
@@ -0,0 +1,11 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <_ansi.h>
+
+int getpid(void)
+{
+	return 1;
+}
diff --git a/libgloss/m68k/atari/atari-gettod.c b/libgloss/m68k/atari/atari-gettod.c
new file mode 100644
index 000000000..5477916a2
--- /dev/null
+++ b/libgloss/m68k/atari/atari-gettod.c
@@ -0,0 +1,135 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <sys/time.h>
+#include <time.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+/*
+	Atari can only handle dates from 1980 to 2107.
+	time_t on m68k is 32bit signed, so that gives us an upper limit of 2038.
+	The code below uses that limitation to simplify the code.
+*/
+
+#define SEC_1900_TO_1980 2524521600
+#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
+#define SECONDS_IN_A_YEAR (365 * SECONDS_IN_A_DAY)
+
+static const short month_to_day[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
+
+int gettimeofday(struct timeval* tv, void* __tz)
+{
+	struct timezone* tz = __tz;
+	if (tz != 0)
+	{
+		// Support for timezone have been removed from linux glibc, so we just fill in a zero timezone.
+		tz->tz_minuteswest = 0;
+		tz->tz_dsttime = 0;
+	}
+	if (tv != 0)
+	{
+		unsigned short date = trap1_2a();
+		unsigned short time = trap1_2c();
+
+		int year = ((date >> 9) & 0x7f);	// from 1980
+		int month = ((date >> 5) & 0xf) - 1;
+		int day = date & 0x1f;
+		int hour = ((time >> 11) & 0x1f);
+		int min = ((time >> 5) & 0x3f);
+		int sec = (time & 0x1f) * 2;
+
+		// Days passed in current year
+		time_t days = day + month_to_day[month];
+		// Add days for every passed year
+		days += year * 365;
+
+		// Add days for every passed leap year
+		int months = year * 12 + month;	// total months
+		months -= 2;	// remove januari and februari
+		if (months > 0)
+		{
+			// We must have passed at least one leap day.
+			int leap_days = (months / (12*4)) + 1;
+			days += leap_days;
+		}
+
+		// Add it all together
+		tv->tv_sec = (((((days * 24) + hour) * 60) + min) * 60) + sec + SEC_1900_TO_1980;
+		tv->tv_usec = 0;
+	}
+	return 0;
+}
+
+int settimeofday(const struct timeval* tv, const struct timezone* tz)
+{
+	// Support for timezone have been removed from linux glibc, so we just ignore it.
+	if (tv != 0)
+	{
+		if (tv->tv_sec < SEC_1900_TO_1980 || tv->tv_sec >= SEC_1900_TO_MAX)
+		{
+			// Outside the ranges we can handle.
+			gem_error_to_errno(GEM_EBADRQ);
+			return -1;
+		}
+
+		time_t seconds = tv->tv_sec - SEC_1900_TO_1980;
+		int year = 0;
+		time_t ysec = SECONDS_IN_A_YEAR;
+		do
+		{
+			ysec = SECONDS_IN_A_YEAR;
+			if ((year % 4) == 0)
+			{
+				ysec += SECONDS_IN_A_DAY;
+			}
+			++year;
+			seconds -= ysec;
+		} while (seconds >= 0);
+		--year;
+		seconds += ysec;
+
+		int minutes = seconds / 60;
+		int hours = minutes / 60;
+		int days = hours / 24;
+		int month = 0;
+		int leap = year % 4;
+		short ld = month_to_day[0];
+		for (int m = 0; m < 12; ++m)
+		{
+			short d = month_to_day[m + 1];
+			if (leap == 0 && m > 0) {d += 1;}
+			if (d > days)
+			{
+				month = m;
+				days -= ld;
+				break;
+			}
+			ld = d;
+		}
+
+		unsigned short date = (unsigned short)(year << 9);
+		date |= (unsigned short)((month + 1) << 5);
+		date |= (unsigned short)days;
+		unsigned short time = (unsigned short)((hours % 24) << 11);
+		time |= (unsigned short)((minutes % 60) << 5);
+		time |= (unsigned short)((seconds % 60) >> 1);
+
+		int err;
+		if ((err = trap1_2b(date)) < 0)
+		{
+			gem_error_to_errno(err);
+			return -1;
+		}
+		if ((err = trap1_2d(time)) < 0)
+		{
+			gem_error_to_errno(err);
+			return -1;
+		}
+	}
+	return 0;
+}
diff --git a/libgloss/m68k/atari/atari-isatty.c b/libgloss/m68k/atari/atari-isatty.c
new file mode 100644
index 000000000..5ab8b9aff
--- /dev/null
+++ b/libgloss/m68k/atari/atari-isatty.c
@@ -0,0 +1,12 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <_ansi.h>
+#include "atari-traps.h"
+
+int isatty(int fd)
+{
+	return fd == GSH_AUX ? 1 : 0;
+}
diff --git a/libgloss/m68k/atari/atari-kill.c b/libgloss/m68k/atari/atari-kill.c
new file mode 100644
index 000000000..cd1d16065
--- /dev/null
+++ b/libgloss/m68k/atari/atari-kill.c
@@ -0,0 +1,16 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+
+/*
+ * kill -- go out via exit...
+ */
+int kill(int pid, int sig)
+{
+	_exit(sig);
+	return 0;
+}
diff --git a/libgloss/m68k/atari/atari-link.c b/libgloss/m68k/atari/atari-link.c
new file mode 100644
index 000000000..e5a1485e5
--- /dev/null
+++ b/libgloss/m68k/atari/atari-link.c
@@ -0,0 +1,19 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <_syslist.h>
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include "libnosys/warning.h"
+
+int link(char *old, char *new)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+stub_warning(link)
diff --git a/libgloss/m68k/atari/atari-lseek.c b/libgloss/m68k/atari/atari-lseek.c
new file mode 100644
index 000000000..fa703253d
--- /dev/null
+++ b/libgloss/m68k/atari/atari-lseek.c
@@ -0,0 +1,43 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+	int newoff = GEM_EIHNDL;
+	if (fd >= 0 && fd <= 2)
+	{
+		// stdin, stdout and stderr just returns OK without doing anything.
+		return 0;
+	}
+	else if (fd >= 3)
+	{
+		// Any file descriptor
+		unsigned short bios_mode = 3; // invalid mode
+		switch (whence)
+		{
+		case SEEK_SET:
+			bios_mode = 0;
+			break;
+		case SEEK_CUR:
+			bios_mode = 1;
+			break;
+		case SEEK_END:
+			bios_mode = 2;
+			break;
+		}
+		newoff = trap1_42((unsigned int)offset, (unsigned short)fd, bios_mode);
+	}
+	if (newoff < 0)
+	{
+		gem_error_to_errno(newoff);
+		return (off_t)-1;
+	}
+	return (off_t)newoff;
+}
diff --git a/libgloss/m68k/atari/atari-mkdir.c b/libgloss/m68k/atari/atari-mkdir.c
new file mode 100644
index 000000000..fdff26b4c
--- /dev/null
+++ b/libgloss/m68k/atari/atari-mkdir.c
@@ -0,0 +1,21 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+int mkdir(const char *pathname, mode_t mode)
+{
+	// Ignore mode, it is not supported by the st.
+	int result = trap1_39(pathname);
+	if (result < 0)
+	{
+		gem_error_to_errno(result);
+		return -1;
+	}
+	return 0;
+}
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-open.c b/libgloss/m68k/atari/atari-open.c
new file mode 100644
index 000000000..c61071881
--- /dev/null
+++ b/libgloss/m68k/atari/atari-open.c
@@ -0,0 +1,78 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+// I really don't like having these defines here,
+// fcntl.h where they are, also defines a function for "open",
+// that is different from the one libgloss is supposed to provide...
+#ifndef O_CREAT
+#define O_CREAT 0x0200
+#endif // O_CREAT
+#ifndef O_APPEND
+#define O_APPEND 0x0008
+#endif // O_APPEND
+#ifndef O_EXCL
+#define O_EXCL 0x0800
+#endif // O_EXCL
+#ifndef O_TRUNC
+#define O_TRUNC 0x0400
+#endif // O_TRUNC
+
+// mode is ignored. Those kind of settings is not supported by the st.
+int open(const char *buf, int flags, int mode)
+{
+	int bios_handle = -1;
+	unsigned short bios_mode = (unsigned short)(flags & 0x3); // bits 0-1 the same for st and linux.
+	int create = flags & O_CREAT;
+	int append = flags & O_APPEND; // open doc says that seek end should be done before each write call. We assume that newlib handles that.
+	int excl = flags & O_EXCL;	   // File must be created by this call.
+	int trunc = flags & O_TRUNC;   // File is forced to be created and thus truncated.
+
+	const char *bios_path = buf;
+	if (!trunc)
+	{
+		bios_handle = trap1_3d(bios_path, bios_mode);
+	}
+	if (bios_handle < 0 && (create || trunc))
+	{
+		unsigned short bios_attrib = 0;
+		bios_handle = trap1_3c(bios_path, bios_attrib);
+	}
+	else if (create && excl)
+	{
+		// We explicitly specified that file must be created, and it already existed, so error!
+		gem_error_to_errno(GEM_EACCDN);
+		// Close file.
+		trap1_3e((unsigned short)bios_handle);
+		return -1;
+	}
+
+	if (bios_handle >= 0 && append)
+	{
+		// Seek to end.
+		int new_file_pos = trap1_42(0, (unsigned short)bios_handle, 2);
+		if (new_file_pos < 0)
+		{
+			gem_error_to_errno(new_file_pos);
+			// Close file.
+			trap1_3e((unsigned short)bios_handle);
+			return -1;
+		}
+	}
+
+	if (bios_handle < 0)
+	{
+		gem_error_to_errno(bios_handle);
+		bios_handle = -1;
+	}
+	/*
+		If bios_handle is positive, then the low word is the gemdos handle, and the high word is zero.
+	*/
+	return bios_handle;
+}
diff --git a/libgloss/m68k/atari/atari-read.c b/libgloss/m68k/atari/atari-read.c
new file mode 100644
index 000000000..cdff256e7
--- /dev/null
+++ b/libgloss/m68k/atari/atari-read.c
@@ -0,0 +1,44 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+_READ_WRITE_RETURN_TYPE read(int fd, void *buf, size_t nbytes)
+{
+	int numRead = GEM_EIHNDL;
+	if (fd >= 0)
+	{
+		numRead = trap1_3f((unsigned short)fd, nbytes, buf);
+		if (numRead >= 0 && numRead < nbytes && fd == GSH_CONIN)
+		{
+			/*
+				When reading from console, the EOF character is "\n".
+				Atari tos do not return the EOF character, but posix read do.
+				So we assume that when the trap call have not reached the nbytes limit,
+				then it must have gotten an EOF.
+				So in that case we insert "\n" to the end of the buffer and increase lenth by 1.
+			*/
+			((char*)buf)[numRead] = '\n';
+			++numRead;
+			/*
+				This is not enough however...
+				Atari tos requires a line feed to be "\r\n", and apparently, the "\r" is executed by tos
+				but not returned when reading. This is not a problem for us, but the "\n" as it is an EOF
+				is simply discarded and not executed. So we also need to send a "\n" to stdout to fully comply
+				with standard C behaviour.
+			*/
+			trap1_40(GSH_CONOUT, 1, "\n");
+		}
+	}
+	if (numRead < 0)
+	{
+		gem_error_to_errno(numRead);
+		return -1;
+	}
+	return numRead;
+}
diff --git a/libgloss/m68k/atari/atari-readlink.c b/libgloss/m68k/atari/atari-readlink.c
new file mode 100644
index 000000000..23514a151
--- /dev/null
+++ b/libgloss/m68k/atari/atari-readlink.c
@@ -0,0 +1,20 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <_syslist.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include "libnosys/warning.h"
+
+int readlink(const char *path, char *buf, size_t bufsize)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+stub_warning(readlink)
diff --git a/libgloss/m68k/atari/atari-rename.c b/libgloss/m68k/atari/atari-rename.c
new file mode 100644
index 000000000..2d7e62da2
--- /dev/null
+++ b/libgloss/m68k/atari/atari-rename.c
@@ -0,0 +1,20 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+int _rename(const char *old_filename, const char *new_filename)
+{
+	int err = trap1_56(old_filename, new_filename);
+	if (err < 0)
+	{
+		gem_error_to_errno(err);
+		return -1;
+	}
+	return 0;
+}
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-rmdir.c b/libgloss/m68k/atari/atari-rmdir.c
new file mode 100644
index 000000000..647a5b68f
--- /dev/null
+++ b/libgloss/m68k/atari/atari-rmdir.c
@@ -0,0 +1,20 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+int rmdir(const char *pathname)
+{
+	int result = trap1_3a(pathname);
+	if (result < 0)
+	{
+		gem_error_to_errno(result);
+		return -1;
+	}
+	return 0;
+}
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-sbrk.c b/libgloss/m68k/atari/atari-sbrk.c
new file mode 100644
index 000000000..8839cc742
--- /dev/null
+++ b/libgloss/m68k/atari/atari-sbrk.c
@@ -0,0 +1,24 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <errno.h>
+#include <_ansi.h>
+
+extern char *_HeapPtr;
+extern char *_HeapBottom;
+extern char *_HeapTop;
+
+char *sbrk(int nbytes)
+{
+	char *newheap = _HeapPtr + nbytes;
+	if (newheap > _HeapTop)
+	{
+		errno = ENOMEM;
+		return ((char *)-1);
+	}
+	char *retptr = _HeapPtr;
+	_HeapPtr = newheap;
+	return retptr;
+}
diff --git a/libgloss/m68k/atari/atari-stat.c b/libgloss/m68k/atari/atari-stat.c
new file mode 100644
index 000000000..a08273204
--- /dev/null
+++ b/libgloss/m68k/atari/atari-stat.c
@@ -0,0 +1,29 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+
+// I don't like this extern declaration here...
+extern int open(const char *buf, int flags, int mode);
+
+int stat(const char *path, struct stat *buf)
+{
+	int handle = open(path, 0, 0); // read only
+	if (handle >= 0)
+	{
+		int err = fstat(handle, buf);
+		close(handle);
+		handle = err;
+	}
+	if (handle < 0)
+	{
+		gem_error_to_errno(handle);
+		return -1;
+	}
+	return 0;
+}
diff --git a/libgloss/m68k/atari/atari-symlink.c b/libgloss/m68k/atari/atari-symlink.c
new file mode 100644
index 000000000..49bc31886
--- /dev/null
+++ b/libgloss/m68k/atari/atari-symlink.c
@@ -0,0 +1,19 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <_syslist.h>
+#include <errno.h>
+#include "atari-gem_errno.h"
+#include "libnosys/warning.h"
+
+int symlink(const char *path1, const char *path2)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+stub_warning(symlink)
diff --git a/libgloss/m68k/atari/atari-times.c b/libgloss/m68k/atari/atari-times.c
new file mode 100644
index 000000000..5c825c6ff
--- /dev/null
+++ b/libgloss/m68k/atari/atari-times.c
@@ -0,0 +1,37 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <time.h>
+#include <sys/times.h>
+#include "atari-traps.h"
+#include "atari-gem_errno.h"
+
+// Defined and initialized in atari-crti.S
+extern unsigned int _atari_4ba_at_prg_start;
+
+
+// The memory location read is actually unsigned, so we cast that in the caller func.
+int read200hzMem(void)
+{
+	// 0x4ba is a privileged address only readable in supervisor mode.
+	return *((int*)0x4ba);
+}
+
+clock_t times(struct tms *buf)
+{
+	// Call callback in supervisor mode.
+	unsigned long long int ticks200hz = (unsigned long long int)trap14_26(read200hzMem);
+	unsigned long long int libcticks = (ticks200hz * CLK_TCK) / 200;
+
+	unsigned long long int processticks = ((unsigned long long int)_atari_4ba_at_prg_start * CLK_TCK) / 200;
+	processticks = libcticks - processticks;
+
+	// For a single threaded system like the atari, only tms_utime is meaningful.
+	buf->tms_utime = (clock_t)processticks;
+	buf->tms_stime = 0;
+	buf->tms_cutime = 0;
+	buf->tms_cstime = 0;
+	return (clock_t)libcticks;
+}
diff --git a/libgloss/m68k/atari/atari-tos.ld b/libgloss/m68k/atari/atari-tos.ld
new file mode 100644
index 000000000..6bbecc261
--- /dev/null
+++ b/libgloss/m68k/atari/atari-tos.ld
@@ -0,0 +1,160 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
+OUTPUT_ARCH(m68k)
+INPUT (crti.o crtn.o crt0.o)
+
+SECTIONS
+{
+	/*
+	Start all addresses at 0.
+	That way, the relocation is a bit easier when converting to prg.
+	*/
+	. = 0x0;
+	.text : {
+		*crti.o(.init)
+		*crtbegin.o(.init)
+		*crtend.o(.init)
+		*crtn.o(.init)
+		*crt0.o(.init)
+		*crti.o(.fini)
+		*crtbegin.o(.fini)
+		*crtend.o(.fini)
+		*crtn.o(.fini)
+		*(.text*)
+		*(.gnu.warning)
+		FILL(0x0000);
+		. = ALIGN(0x4);
+	}
+	/*
+		There is no rodata in a prg file, so we store all data in .data section.
+	*/
+	.data BLOCK(0x4) : {
+		__DATA_SEGMENT__ = .;
+		*(.data*);
+		. = ALIGN(0x4);
+		*(.rodata*);
+		. = ALIGN(0x4);
+
+		*(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*)
+		*(.eh_frame) *(.eh_frame.*)
+		*(.sframe) *(.sframe.*)
+		*(.gcc_except_table .gcc_except_table.*)
+		*(.gnu_extab*)
+
+		/*
+			All constructors
+		*/
+		KEEP (*crtbegin.o(.ctors))
+		KEEP (*crtbegin?.o(.ctors))
+		KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+		KEEP (*(SORT(.ctors.*)))
+		KEEP (*(.ctors))
+
+		/*
+			All destructors
+		*/
+		KEEP (*crtbegin.o(.dtors))
+		KEEP (*crtbegin?.o(.dtors))
+		KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+		KEEP (*(SORT(.dtors.*)))
+		KEEP (*(.dtors))
+
+		FILL(0x0000);
+		. = ALIGN(0x4);
+	}
+	.bss BLOCK(0x4) : {
+		__BSS_SEGMENT__ = .;
+		*(.bss);
+		. = ALIGN(0x4);
+		*(COMMON);
+		. = ALIGN(0x4);
+	}
+	__BSS_SEGMENT_END = .;
+
+	/*
+	Atari Prg header.
+	We don't care what the address is for this.
+	*/
+	.prgheader : {
+		SHORT(0x601a); 								/* Branch to start of the program  (must be 0x601a, used as magic number!) */
+		LONG(__DATA_SEGMENT__);						/* Length of the TEXT segment */
+		LONG(__BSS_SEGMENT__ - __DATA_SEGMENT__);	/* Length of the DATA segment */
+		LONG(__BSS_SEGMENT_END - __BSS_SEGMENT__);	/* Length of the BSS segment */
+		LONG(0);									/* Length of the symbol table */
+		LONG(0);									/* Reserved, should be 0 */
+		LONG(0);									/* Program flags */
+		SHORT(0);									/*  0 = Relocation info present */
+	}
+
+	.note.gnu.build-id  : { *(.note.gnu.build-id) }
+	.interp         : { *(.interp) }
+	.hash           : { *(.hash) }
+	.gnu.hash       : { *(.gnu.hash) }
+	.dynsym         : { *(.dynsym) }
+	.dynstr         : { *(.dynstr) }
+	.gnu.version    : { *(.gnu.version) }
+	.gnu.version_d  : { *(.gnu.version_d) }
+	.gnu.version_r  : { *(.gnu.version_r) }
+
+	/* Stabs debugging sections.  */
+	.stab          0 : { *(.stab) }
+	.stabstr       0 : { *(.stabstr) }
+	.stab.excl     0 : { *(.stab.excl) }
+	.stab.exclstr  0 : { *(.stab.exclstr) }
+	.stab.index    0 : { *(.stab.index) }
+	.stab.indexstr 0 : { *(.stab.indexstr) }
+	.comment 0 (INFO) : { *(.comment); LINKER_VERSION; }
+	.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
+
+	/* DWARF debug sections.
+		Symbols in the DWARF debugging sections are relative to the beginning
+		of the section so we begin them at 0.
+	*/
+	/* DWARF 1.  */
+	.debug          0 : { *(.debug) }
+	.line           0 : { *(.line) }
+
+	/* GNU DWARF 1 extensions.  */
+	.debug_srcinfo  0 : { *(.debug_srcinfo) }
+	.debug_sfnames  0 : { *(.debug_sfnames) }
+
+	/* DWARF 1.1 and DWARF 2.  */
+	.debug_aranges  0 : { *(.debug_aranges) }
+	.debug_pubnames 0 : { *(.debug_pubnames) }
+
+	/* DWARF 2.  */
+	.debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+	.debug_abbrev   0 : { *(.debug_abbrev) }
+	.debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end) }
+	.debug_frame    0 : { *(.debug_frame) }
+	.debug_str      0 : { *(.debug_str) }
+	.debug_loc      0 : { *(.debug_loc) }
+	.debug_macinfo  0 : { *(.debug_macinfo) }
+
+	/* SGI/MIPS DWARF 2 extensions.  */
+	.debug_weaknames 0 : { *(.debug_weaknames) }
+	.debug_funcnames 0 : { *(.debug_funcnames) }
+	.debug_typenames 0 : { *(.debug_typenames) }
+	.debug_varnames  0 : { *(.debug_varnames) }
+
+	/* DWARF 3.  */
+	.debug_pubtypes 0 : { *(.debug_pubtypes) }
+	.debug_ranges   0 : { *(.debug_ranges) }
+
+	/* DWARF 5.  */
+	.debug_addr     0 : { *(.debug_addr) }
+	.debug_line_str 0 : { *(.debug_line_str) }
+	.debug_loclists 0 : { *(.debug_loclists) }
+	.debug_macro    0 : { *(.debug_macro) }
+	.debug_names    0 : { *(.debug_names) }
+	.debug_rnglists 0 : { *(.debug_rnglists) }
+	.debug_str_offsets 0 : { *(.debug_str_offsets) }
+	.debug_sup      0 : { *(.debug_sup) }
+	.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+	/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }
+
+}
\ No newline at end of file
diff --git a/libgloss/m68k/atari/atari-tos.specs b/libgloss/m68k/atari/atari-tos.specs
new file mode 100644
index 000000000..00781c4fc
--- /dev/null
+++ b/libgloss/m68k/atari/atari-tos.specs
@@ -0,0 +1,10 @@
+#	Copyright (C) 2025 Mikael Hildenborg
+#	SPDX-License-Identifier: BSD-2-Clause
+
+# Atari gcc specs
+
+*link:
++ --emit-relocs --no-warn-rwx-segments -static --no-warn-execstack --undefined=__errno -T atari-tos.ld
+
+*lib:
++ -latari-tos
diff --git a/libgloss/m68k/atari/atari-traps.c b/libgloss/m68k/atari/atari-traps.c
new file mode 100644
index 000000000..c387ff144
--- /dev/null
+++ b/libgloss/m68k/atari/atari-traps.c
@@ -0,0 +1,311 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "atari-traps.h"
+
+// Store stack pointer in a3, that by Atari documentation will be left untouched by the trap call.
+#define TRAP_BEGIN "move.l		%%a7, %%a3\n\t"
+// Make trap call and then restore the stack pointer from the stored value in a3
+#define TRAP_FUNC(num, func) "move.w		#" #func ", %%a7@-\n\ttrap		#" #num "\n\tmove.l		%%a3, %%a7\n\t"
+// Registers d1,d2 and a0, a1, a2 may be affected by trap #1 calls. Register a3 is used to store/restore a7
+#define CLOBBER_REG "d1", "d2", "a0", "a1", "a2", "a3"
+
+unsigned int trap1_e(unsigned short bios_drive)
+{
+	register unsigned int bios_mounted_drives asm ("d0") = 0;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0xe)
+		: "=r" (bios_mounted_drives)
+		: "r" (bios_drive)
+		: CLOBBER_REG);
+	return bios_mounted_drives;
+}
+
+unsigned short trap1_19(void)
+{
+	register unsigned short bios_drive asm ("d0") = 0;
+	__asm__ volatile (
+		TRAP_BEGIN
+		TRAP_FUNC(1, 0x19)
+		: "=r" (bios_drive)
+		:
+		: CLOBBER_REG);
+	return bios_drive;
+}
+
+unsigned short trap1_2a(void)
+{
+	register unsigned short date asm ("d0") = 0;
+	__asm__ volatile (
+		TRAP_BEGIN
+		TRAP_FUNC(1, 0x2a)
+		: "=r" (date)
+		:
+		: CLOBBER_REG);
+	return date;
+}
+
+int trap1_2b(unsigned short date)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x2b)
+		: "=r" (result)
+		:"r" (date)
+		: CLOBBER_REG);
+	return result;
+}
+
+unsigned short trap1_2c(void)
+{
+	register unsigned short time asm ("d0") = 0;
+	__asm__ volatile (
+		TRAP_BEGIN
+		TRAP_FUNC(1, 0x2c)
+		: "=r" (time)
+		:
+		: CLOBBER_REG);
+	return time;
+}
+
+int trap1_2d(unsigned short time)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x2d)
+		: "=r" (result)
+		:"r" (time)
+		: CLOBBER_REG);
+	return result;
+}
+
+
+struct DTA* trap1_2f(unsigned short bios_handle)
+{
+	register struct DTA* result asm ("d0") = (struct DTA*)-1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x2f)
+		: "=r" (result)
+		: "r" (bios_handle)
+		: CLOBBER_REG);
+	return result;
+}
+
+
+int trap1_39(const char* bios_path)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x39)
+		: "=r" (result)
+		: "r" (bios_path)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_3a(const char* bios_path)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x3a)
+		: "=r" (result)
+		: "r" (bios_path)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_3b(const char* bios_path)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x3b)
+		: "=r" (result)
+		: "r" (bios_path)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_3c(const char* bios_path, unsigned short bios_attrib)
+{
+	register int bios_handle asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%2, %%a7@-\n\t"
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x3c)
+		: "=r" (bios_handle)
+		: "r" (bios_path), "r" (bios_attrib)
+		: CLOBBER_REG);
+	return bios_handle;
+}
+
+int trap1_3d(const char* bios_path, unsigned short bios_mode)
+{
+	register int bios_handle asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%2, %%a7@-\n\t"
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x3d)
+		: "=r" (bios_handle)
+		: "r" (bios_path), "r" (bios_mode)
+		: CLOBBER_REG);
+	return bios_handle;
+}
+
+int trap1_3e(unsigned short bios_handle)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x3e)
+		: "=r" (result)
+		: "r" (bios_handle)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_3f(unsigned short bios_handle, int length, void* buf)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%3, %%a7@-\n\t"
+		"move.l		%2, %%a7@-\n\t"
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x3f)
+		: "=r" (result)
+		: "r" (bios_handle), "r" (length), "r" (buf)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_40(unsigned short bios_handle, int length, const void* buf)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%3, %%a7@-\n\t"
+		"move.l		%2, %%a7@-\n\t"
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x40)
+		: "=r" (result)
+		: "r" (bios_handle), "r" (length), "r" (buf)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_41(const char* bios_path)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x41)
+		: "=r" (result)
+		: "r" (bios_path)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_42(unsigned int file_position, unsigned short bios_handle, unsigned short bios_mode)
+{
+	register int new_position asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%3, %%a7@-\n\t"
+		"move.w		%2, %%a7@-\n\t"
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x42)
+		: "=r" (new_position)
+		: "r" (file_position), "r" (bios_handle), "r" (bios_mode)
+		: CLOBBER_REG);
+	return new_position;
+}
+
+int trap1_47(char* buf, unsigned short bios_drive)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.w		%2, %%a7@-\n\t"
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x47)
+		: "=r" (result)
+		: "r" (buf), "r" (bios_drive)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_4b(unsigned short mode, const char* file_name, const char* cmdline, const char* envstring)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%4, %%a7@-\n\t"
+		"move.l		%3, %%a7@-\n\t"
+		"move.l		%2, %%a7@-\n\t"
+		"move.w		%1, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x4b)
+		: "=r" (result)
+		: "r" (mode), "r" (file_name), "r" (cmdline), "r" (envstring)
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap1_56(const char* oldname, const char* newname)
+{
+	register int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%2, %%a7@-\n\t"
+		"move.l		%1, %%a7@-\n\t"
+		"move.w		#0, %%a7@-\n\t"
+		TRAP_FUNC(1, 0x56)
+		: "=r" (result)
+		: "r" (oldname), "r" (newname)
+		: CLOBBER_REG);
+	return result;
+}
+
+unsigned int trap14_11(void)
+{
+	register unsigned int result asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		TRAP_FUNC(14, 0x11)
+		: "=r" (result)
+		:
+		: CLOBBER_REG);
+	return result;
+}
+
+int trap14_26(int (*callback)(void))
+{
+	register int callback_return asm ("d0") = -1;
+	__asm__ volatile (
+		TRAP_BEGIN
+		"move.l		%1, %%a7@-\n\t"
+		TRAP_FUNC(14, 0x26)
+		: "=r" (callback_return)
+		: "r" (callback)
+		: CLOBBER_REG);
+	return callback_return;
+}
diff --git a/libgloss/m68k/atari/atari-traps.h b/libgloss/m68k/atari/atari-traps.h
new file mode 100644
index 000000000..01edb7062
--- /dev/null
+++ b/libgloss/m68k/atari/atari-traps.h
@@ -0,0 +1,84 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#ifndef TRAPS_DEFINED
+#define TRAPS_DEFINED
+
+#include "atari-gem_basepage.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+	Only trap calls used by atari libgloss is included here.
+*/
+
+unsigned int trap1_e(unsigned short bios_drive);
+
+// Returned drive starts at 0 for A
+unsigned short trap1_19(void);
+
+unsigned short trap1_2a(void);
+
+int trap1_2b(unsigned short date);
+
+unsigned short trap1_2c(void);
+
+int trap1_2d(unsigned short time);
+
+struct DTA* trap1_2f(unsigned short bios_handle);
+
+int trap1_39(const char* bios_path);
+
+int trap1_3a(const char* bios_path);
+
+int trap1_3b(const char* bios_path);
+
+int trap1_3c(const char* bios_path, unsigned short bios_attrib);
+
+int trap1_3d(const char* bios_path, unsigned short bios_mode);
+
+#define GSH_BIOSCON		0xFFFF
+#define GSH_BIOSAUX		0xFFFE
+#define GSH_BIOSPRN		0xFFFD
+#define GSH_BIOSMIDIIN	0xFFFC
+#define GSH_BIOSMIDIOUT	0xFFFB
+#define GSH_CONIN		0x00
+#define GSH_CONOUT		0x01
+#define GSH_AUX			0x02
+#define GSH_PRN			0x03
+
+int trap1_3e(unsigned short bios_handle);
+
+int trap1_3f(unsigned short bios_handle, int length, void* buf);
+
+int trap1_40(unsigned short bios_handle, int length, const void* buf);
+
+int trap1_41(const char* bios_path);
+
+int trap1_42(unsigned int file_position, unsigned short bios_handle, unsigned short bios_mode);
+
+// bios_drive 0 is default drive, and 1 and upwards is A...
+int trap1_47(char* buf, unsigned short bios_drive);
+
+#define PE_LOADGO		0
+#define PE_LOAD			3
+#define PE_GO			4
+#define PE_BASEPAGE		5
+#define PE_GOTHENFREE	6
+int trap1_4b(unsigned short mode, const char* file_name, const char* cmdline, const char* envstring);
+
+int trap1_56(const char* oldname, const char* newname);
+
+unsigned int trap14_11(void);
+
+int trap14_26(int (*callback)(void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TRAPS_DEFINED
diff --git a/libgloss/m68k/atari/atari-unlink.c b/libgloss/m68k/atari/atari-unlink.c
new file mode 100644
index 000000000..cacafcf5e
--- /dev/null
+++ b/libgloss/m68k/atari/atari-unlink.c
@@ -0,0 +1,19 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+int unlink(char *path)
+{
+	int err = trap1_41(path);
+	if (err < 0)
+	{
+		gem_error_to_errno(err);
+		return -1;
+	}
+	return 0;
+}
diff --git a/libgloss/m68k/atari/atari-wait.c b/libgloss/m68k/atari/atari-wait.c
new file mode 100644
index 000000000..946419305
--- /dev/null
+++ b/libgloss/m68k/atari/atari-wait.c
@@ -0,0 +1,16 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include "config.h"
+#include <errno.h>
+#include "libnosys/warning.h"
+
+int wait(int *status)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+stub_warning(wait)
diff --git a/libgloss/m68k/atari/atari-write.c b/libgloss/m68k/atari/atari-write.c
new file mode 100644
index 000000000..9d6e59ed8
--- /dev/null
+++ b/libgloss/m68k/atari/atari-write.c
@@ -0,0 +1,87 @@
+/*
+	Copyright (C) 2025 Mikael Hildenborg
+	SPDX-License-Identifier: BSD-2-Clause
+*/
+
+#include <unistd.h>
+#include <_ansi.h>
+#include "atari-gem_errno.h"
+#include "atari-traps.h"
+
+const char* lineEnding = "\r\n";
+
+int writeUntilDoneOrError(int fd, size_t len, const char* buf)
+{
+	size_t written = 0;
+	if (len == 0)
+	{
+		return 0;
+	}
+	do
+	{
+		int n = trap1_40((unsigned short)fd, len, buf);
+		if (n < 0)
+		{
+			gem_error_to_errno(n);
+			return -1;
+		}
+		written += n;
+		buf += n;
+	} while (written < len);
+	return 0;
+}
+
+
+_READ_WRITE_RETURN_TYPE write(int fd, const void *buf, size_t nbytes)
+{
+	int numWritten = GEM_EIHNDL;
+	if (fd >= 0)
+	{
+		if (fd == 2)
+		{
+			fd = GSH_CONOUT; // Use console out for stderr.
+		}
+		if (fd == GSH_CONOUT)
+		{
+			// When we write to stdout on Atari, we must add a \r after \n to
+			// get the correct C output behaviour.
+			const char* stream = (const char*)buf;
+			size_t lastWrite = 0;
+			for (size_t i = 0; i < nbytes; ++i)
+			{
+				if (stream[i] == '\n')
+				{
+					int len = i - lastWrite; // length up to but not including \n
+					if (writeUntilDoneOrError(fd, len, stream + lastWrite) < 0)
+					{
+						return -1;
+					}
+					if (writeUntilDoneOrError(fd, 2, lineEnding) < 0)
+					{
+						return -1;
+					}
+					lastWrite = i + 1;	// Include the \n
+				}
+			}
+			if (lastWrite < nbytes)
+			{
+				int len = nbytes - lastWrite;
+				if (writeUntilDoneOrError(fd, len, stream + lastWrite) < 0)
+				{
+					return -1;
+				}
+			}
+			numWritten = nbytes;
+		}
+		else
+		{
+			numWritten = trap1_40((unsigned short)fd, nbytes, buf);
+		}
+	}
+	if (numWritten < 0)
+	{
+		gem_error_to_errno(numWritten);
+		return -1;
+	}
+	return numWritten;
+}
diff --git a/newlib/configure.host b/newlib/configure.host
index 89564c0b6..960cca215 100644
--- a/newlib/configure.host
+++ b/newlib/configure.host
@@ -252,7 +252,6 @@ case "${host_cpu}" in
   mips*)
 	machine_dir=mips
 	libm_machine_dir=mips
-	newlib_cflags="${newlib_cflags}"
 	;;
   mmix)
 	;;
@@ -769,6 +768,10 @@ newlib_cflags="${newlib_cflags} -DCLOCK_PROVIDED -DMALLOC_PROVIDED -DEXIT_PROVID
 	newlib_cflags="${newlib_cflags} -DHAVE_RENAME -DHAVE_SYSTEM -DMISSING_SYSCALL_NAMES"
 	syscall_dir=
 	;;
+  m68k-atari-elf)
+	newlib_cflags="${newlib_cflags} -DHAVE_RENAME -DMISSING_SYSCALL_NAMES"
+	syscall_dir=
+	;;
   mcore-*-*)
 	syscall_dir=syscalls
 	;;
-- 
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.