Undefined reference to `_exit' and friends

I'm not a compiler guy, so I don't know the correct resolution to this issue, but at least I can describe it. While working in C, I ran across a set of curious errors once I made a call to sprintf():

[...]/stdlib/abort.c:59: undefined reference to `_exit'
[...]/reent/signalr.c:53: undefined reference to `_kill'
[...]/reent/signalr.c:83: undefined reference to `_getpid'
[...]/reent/writer.c:49: undefined reference to `_write'
[...]/reent/closer.c:47: undefined reference to `_close'
[...]/reent/fstatr.c:55: undefined reference to `_fstat'
[...]/reent/isattyr.c:52: undefined reference to `_isatty'
[...]/reent/lseekr.c:49: undefined reference to `_lseek'
[...]/reent/readr.c:49: undefined reference to `_read'

Removing the calls to sprintf() got these errors to go away.

Stack Overflow suggests this thread, which pretty accurately describes my situation. The suggested solution is to compile with --specs=nosys.specs for reasons that kind of went over my head. I added the switch into C_API/buildsupport/common.mk in the recipe for pdex.elf (line 145 in the 1.12.0 SDK) and I was able to compile with no issue.

There may be other standard C functions that cause this to pop up. If all else fails, the above solution does appear to get around the issue without introducing any new ones.

1 Like

The problem is newlib's sprintf() links to some odd system functions you wouldn't expect and which aren't available in the scope of the game. I don't recall off the top of my head what limitations --specs=nosys.specs has, but if the linker doesn't have any complaints it seems like it should be fine. I've got setup.c shims working for printf(), snprintf(), and asprintf(), like we have for malloc etc., will get those into a future update. I didn't include sprintf() since it's always better to use snprintf().. but I'll think about adding that too.

1 Like

Please provide more information on how to fix this. Where exactly I have to put --specs=nosys.specs or what does I added the switch into C_API/buildsupport/common.mk in the recipe for pdex.elf (line 145 in the 1.12.0 SDK) ? What is switch? Switch operator? how once can add switch operator to a line like $(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@? I tried to add to cmake command but no luck. Thanks

In file C_API/buildsupport/common.mk, there is a recipe for a file called /pdx.elf:

$(OBJDIR)/pdex.elf: $(OBJS) $(LDSCRIPT)
	$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@

--specs=nosys.specs goes somewhere in the recipe, such as this:

$(OBJDIR)/pdex.elf: $(OBJS) $(LDSCRIPT)
	$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@ --specs=nosys.specs
1 Like

Linking this post detailing some additional steps for Visual Studio.

I'm having similar issues with sscanf

c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-closer.o): in function `_close_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/closer.c:47: warning: _close is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-fstatr.o): in function `_fstat_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/fstatr.c:55: warning: _fstat is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-signalr.o): in function `_getpid_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/signalr.c:83: warning: _getpid is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-isattyr.o): in function `_isatty_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/isattyr.c:52: warning: _isatty is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-signalr.o): in function `_kill_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/signalr.c:53: warning: _kill is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-lseekr.o): in function `_lseek_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/lseekr.c:49: warning: _lseek is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-readr.o): in function `_read_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/readr.c:49: warning: _read is not implemented and will always fail
c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/progra~2/armgnu~1/1142da~1.3re/bin/../lib/gcc/arm-none-eabi/11.3.1/thumb/v7e-m+fp/hard\libc.a(libc_a-writer.o): in function `_write_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/writer.c:49: warning: _write is not implemented and will always fail

I'm not comfortable with workarounds that involve altering SDK make/etc. files directly, as they'd just disappear (and then break the build) when updating the SDK :wink:

At this point, I'll just roll my own alternative. It would help, though, if there were a definitive (white?)list of what is actually supported from the C libraries. :slight_smile:

Or, is there a definitive list of things from the C libraries that aren't supported?

Edit: I had to go and tweak common.mk anyway, as I kept running into more and more 'things that aren't supported' (atof, strtof, etc. etc.). I made a copy of it with the changes and set it aside to remind me to tweak common.mk again when updating the SDK.

Edit edit: no, this still isn't working. Looks like I get to write my own 'atof' from scratch... fun!

(note to self: no matter how cute the console may look, remember that it's an embedded system - you don't get all the bells and whistles and should expect this sort of thing :slight_smile: )

1 Like

I understand being cautious around the idea of adding a flag to the makefile every time the SDK is updated, but I do want to suggest that there are some good reasons one might want to do it. You gain access to optimized versions of these functions that are maintained by people who have spent a lot more time working on the problem than we ever will.

Well, I did try adding the flag, but it didn't work for me (I probably fumbled it in some way).

IMO if the infrastructure needs to be tweaked it should be done by Panic, as they know what they're actually doing (and I certainly don't :wink: ).

1 Like

Well, managed to muddle through (the whole sscanf/atof thing was about parsing 3D .obj files, got it working ok writing my own primitives):

tertius_texture_mapped_cube_via_mirror

tertius_f117_wireframe_backface_culling

1 Like

you can use playdate->system->formatstring instead of sprintf not sure for sscanf. If using formatstring don't forget that you need to explicitly deallocte the string returned from it.

Unfortunately, formatted printing goes the wrong way (float->text) - I needed (text->float) :slight_smile:

Are you processing user text input? If you are, and sscanf() isn't an option, the algorithm for processing a number from text isn't terribly complicated.

If you're not processing user text input, I suggest preprocessing your data into some binary number format to make things easier on the Playdate end.

Yes, I wrote (actually, stole from the intarwebs :wink: ) an equivalent of 'atoff' and it works a treat.

I'm processing .obj files exported from Blender (obj format details). It was much easier to just write 'atoff' than create an external pre-processing utility to convert .obj to binary.

I've opened the following feature request for an alternative to sscanf():

2 Likes