Is there a list of C standard library function available on Playdate?

,

We're using Playdate SDK on Windows and macOS, both version 2.4.2.

We're trying to make an existing library written in C compatible for Playdate, during which we hit some linker errors where symbols such as _exit not being found.

We came across this thread:

and found out that some of the C standard functions are just not available, so we removed what we could remove (such as calls to vsnprintf, fprintf, sscanf) and started substituting them with Playdate equivalents.

However, even after we've looked everywhere in our code for suspicious standard functions, we're still getting linker errors related to the _exit symbol not being there, and at this point, we're at a loss at what C standard functions are tripping over those symbols.

Is there any list of standard functions available or unavailable on Playdate? If not, is there a way to tell which function is the offender?

FYI, the errors we're getting from macOS SDK reads like the following - just like what the linked thread was talking about:

/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-abort.o): in function `abort':
abort.c:(.text.abort+0xa): undefined reference to `_exit'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-closer.o): in function `_close_r':
closer.c:(.text._close_r+0xc): undefined reference to `_close'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-fstatr.o): in function `_fstat_r':
fstatr.c:(.text._fstat_r+0x12): undefined reference to `_fstat'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-isattyr.o): in function `_isatty_r':
isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-lseekr.o): in function `_lseek_r':
lseekr.c:(.text._lseek_r+0x14): undefined reference to `_lseek'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-readr.o): in function `_read_r':
readr.c:(.text._read_r+0x14): undefined reference to `_read'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-signalr.o): in function `_kill_r':
signalr.c:(.text._kill_r+0x12): undefined reference to `_kill'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-signalr.o): in function `_getpid_r':
signalr.c:(.text._getpid_r+0x0): undefined reference to `_getpid'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-writer.o): in function `_write_r':
writer.c:(.text._write_r+0x14): undefined reference to `_write'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/arm-none-eabi/bin/ld:1:1: build/pdex.elf has a LOAD segment with RWX permissions

Is that with or without --specs=nosys.specs (as suggested in the thread you link to)?

(I don’t have an answer for you – in my project that workaround (of which I have no idea what it does) made all the errors disappear, so I didn’t investigate any further. But if I ever wanted to, I would also be interested in a way of tracing where the references come from.)

With, but we still got the error.

We found the offender, though; in our case, it was assert(expression). It calls abort() inside :man_facepalming:

I'll keep this open in case someone has the solution to this (the way to find the offending functions and/or the list of stdC functions unavailable for use in Playdate).

1 Like

(disclaimer: this is for building on Windows)

Other folks have had similar issues... fix/workaround involved adding some stuff to CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
set(CMAKE_C_STANDARD 11)

set(ENVSDK $ENV{PLAYDATE_SDK_PATH})

#start hack
option(PLATFORM_PLAYDATE "Build for playdate" ON)

if (PLATFORM_PLAYDATE)
  ADD_DEFINITIONS(-DPLATFORM_IMPL_PLAYDATE)
  add_link_options("--specs=nosys.specs")
else()
endif()
#end hack

if (NOT ${ENVSDK} STREQUAL "")
: <etc, etc.>

and adding a redefinition of some of the functions it's complaining about:

// make ARM linker shut up about things we aren't using (nosys lib issues):
void _close(void)
{
}
void _lseek(void)
{

}
void _read(void)
{
}
void _write(void)
{
}
void _fstat(void)
{
}
void _getpid(void)
{
}
void _isatty(void)
{
}
void _kill(void)
{
}
// end ARM linker warning hack
1 Like

That indeed seems to solve the linking issue, but I wonder what happens if we accidentally use one of the forbidden standard functions that happens to link to those.
Have those who tried this workaround experienced a kernel-panic level of crash on PD (i.e., e0 error) every time or does the PD crash only when some kind of abomination with the function occurs (like performing sprintf on a string format %s but the variable given is int)? I don't feel too comfortable about replacing missing symbols with no-op as they might have originally been a fail-safe functions and I'm afraid of destroying our Playdate...