DATA Segment Size Check

Hey Yall

A small thing I ran into last week was having too much stuff in the data segment of the generated binary of a C based game. This came from a few too many global variables. This is easy enough to work around, but it would be good to have a check in the toolchain, as the corresponding crash is pretty hard to understand, and I was just lucky enough to guess the problem relatively early in the debugging process.

Edit: I forgot to note, this crash only happens on device, not on simulator, making it particularly troublesome.

:v:

1 Like

How much memory were you using?
I wonder if the compiler can tell you.

I'm worried now. I dont have hardware yet, maybe my game is doomed...

This isn't about runtime heap or stack memory usage, this "data" is about the set of memory locations set in the layout of a binary itself (see picture); you have data for globals, rodata for string literals, text for code and other stuff I've forgotten about since OS class.

Screenshot 2023-02-05 at 1.12.00 AM

I can try to estimate the size of the data segment later (again, not runtime memory usage), but the stuff generated by the playdate toolchain doesnt seem to play nice with tools I would use to check it out like arm-none-eabi-readelf

1 Like

This seems to work OK:

unix> size -A -d MyGame.pdx/pdex.so | grep -E 'text|data'

.text                 44568   18432
.rodata                5039   65536
.data                  2104   82464

But I'd still like to know if I now need to re-factor all the static data to be dynamically allocated (loaded from file on start-up, for example).

With the full output being:

MyGame.pdx/pdex.so  :
section                size    addr
.note.gnu.property       32     680
.note.gnu.build-id       36     712
.gnu.hash              1252     752
.dynsym                3936    2008
.dynstr                2801    5944
.gnu.version            328    8746
.gnu.version_r           64    9080
.rela.dyn              2088    9144
.rela.plt              1488   11232
.init                    27   16384
.plt                   1008   16416
.plt.got                 16   17424
.plt.sec                992   17440
.text                 44568   18432
.fini                    13   63000
.rodata                5039   65536
.eh_frame_hdr           844   70576
.eh_frame              3400   71424
.init_array               8   80768
.fini_array               8   80776
.dynamic                464   80784
.got                    672   81248
.got.plt                520   81920
.data                  2104   82464
.bss                 179088   84576
.comment                 43       0
.debug_aranges          288       0
.debug_info           99861       0
.debug_abbrev          3996       0
.debug_line           12874       0
.debug_str            16467       0
.debug_line_str         948       0
.debug_rnglists          45       0
Total                385318

This is almost never the case, but I don't have a linux box on me :sweat_smile:(size behaves differently on osx), but that tip is helpful ty @UrlOfSandwich !

One note, I could be wrong but I believe the .so/.dylib/.dll correspond to the simulator build, whereas the .bin corresponds to the device build (source: Inside Playdate with C) so we would need to check that file for the layout (please correct me if I'm misunderstanding!)

Ah, good to know.

So we need to run the arm cross-compiler tools on the .bin.
I found some information about getting gcc to log some of this stuff, but was sidetracked before I could work out if any of it was useful.

I guess the data segment size should be roughly the same between native & arm, unless your data structure layouts are packed really bad. (Back in the olden days, you'd get runtime packing-faults on arm)

EDIT: Hmm, my pdex.bin is empty.

You need to do a separate build step for a device build, your config is probably just building simulator.

About the size difference, it could actually be quite drastic, outside of padding, one example is things like int and size_t which will have different widths based on the platform they are targeting, 64 bits on the simulator, and 32 on the device.

I'm using a CMakeFile.txt I pinched from one of the example C-API projects in the SDK.

It doesn't seem to have any of those simulator/pdc/device targets. make all works though (for a simulator OK, but 0-byte .bin build).

I will have a dig around other example cmake files and see if there's anything useful.

EDIT: Looking at the SDK CMake Files, it looks like you need to define TOOLCHAIN to be armgcc, e.g.:

cmake . -DTOOLCHAIN=armgcc -DCMAKE_BUILD_TYPE=Debug

This still doesn't define those targets, but at least it looks to be building an Arm version. All that said, it doesn't work:

[ 12%] Building C object CMakeFiles/Turret_DEVICE.dir/home/sando/Code/Play.Date     /PlaydateSDK/PlaydateSDK-1.12.3/C_API/buildsupport/setup.c.o
/usr/bin/cc -DTARGET_EXTENSION=1 -DTARGET_PLAYDATE=1 -I/home/sando/Code/Play.Date/PlaydateSDK/PlaydateSDK-1.12.3/C_API -g   -fdata-sections -Wall -Wno-unknown-pragmas -Wdouble-promotion -O2 -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1 -falign-functions=16 -fomit-frame-pointer -gdwarf-2 -fverbose-asm -ffunction-sections -fdata-sections -std=gnu11 -MD -MT CMakeFiles/Turret_DEVICE.dir/home/sando/Code/Play.Date/PlaydateSDK/PlaydateSDK-1.12.3/C_API/buildsupport/setup.c.o -MF CMakeFiles/Turret_DEVICE.dir/home/sando/Code/Play.Date/PlaydateSDK/PlaydateSDK-1.12.3/C_API/buildsupport/setup.c.o.d -o CMakeFiles/Turret_DEVICE.dir/home/sando/Code/Play.Date/PlaydateSDK/PlaydateSDK-1.12.3/C_API/buildsupport/setup.c.o -c /home/sando/Code/Play.Date/PlaydateSDK/PlaydateSDK-1.12.3/C_API/buildsupport/setup.c
cc: warning: β€˜-mcpu=’ is deprecated; use β€˜-mtune=’ or β€˜-march=’ instead
cc: error: unrecognized command-line option β€˜-mthumb’ 
cc: error: unrecognized command-line option β€˜-mfloat-abi=hard’
cc: error: unrecognized command-line option β€˜-mfpu=fpv5-sp-d16’

So the cmake include files, or my compiler is out of date.

What -mtune / -march do I give it? arm? armhf?

I can share my build file, if that helps, but this is pulling a bit off topic from the purpose of the thread so further discussion should probably open a separate issue.

#!/bin/sh

rm -r device_build/CMakeFiles/ device_build/CMakeCache.txt
rm -r sim_build/CMakeFiles/ sim_build/CMakeCache.txt

if [ ! -d "<insert-pdx-name>.pdx" ]; then
  mkdir <insert-pdx-name>.pdx
fi

pushd sim_build/
cmake -DCMAKE_BUILD_TYPE=Release ..
popd

pushd device_build/
cmake -DCMAKE_TOOLCHAIN_FILE=<insert-relevant-path>/PlaydateSDK/C_API/buildsupport/arm.cmake -DCMAKE_BUILD_TYPE=Release ..
popd

pushd sim_build/
rm -r ../<insert-pdx-name>.pdx/ && make clean && make
popd

pushd device_build/
rm -r ../<insert-pdx-name>.pdx && make clean && make
popd

Note: I'm not saying the above script is good, its probably terrible, but it got the build working and I just am too old to mess with build files any more

1 Like

I, um, ... don't have the arm development environment installed on this machine. :roll_eyes:
I'll get that fixed ASAP.