logoalt Hacker News

Neywinyyesterday at 11:16 PM4 repliesview on HN

2 things of notice in the readme as recently I've been in the efficient binary communication hunt:

1. .text size without clarifying the architecture, flags, and compiler is meaningless unless it's all rodata (and it's not)

2. Saying it takes 0 .bss and .data just means it allocates everything elsewhere and that can be helpful to know. Of course in compilation that'll also be dependent on how and for what it's built. To say it's zero alloc is incorrect or at best misleading. Here's a line of code that allocates a ton of stuff on the stack: https://github.com/wolfSSL/wolfCOSE/blob/b90b34abcba90aa7b8a... (previously pointed to another line but it was diluting my thesis). Anyone in embedded who's had to increase stack size to use a fancy function knows what I'm talking about. I'm looking at you, sscanf. Some of this code will allocate hundreds if not low thousands of bytes onto the stack. Which is maybe fine but don't say it's zero alloc just because it's all on the stack.


Replies

amiga386today at 12:48 AM

That line allocates nothing. The function is their version of explicit_bzero(). The line casts an existing pointer passed in (e.g. pointing to something on the stack, or allocated by you) to a volatile pointer, which prevents the compiler from optimising away the writes.

Their README states "zero dynamic allocation: all operations use caller-provided buffers" and "Full COSE lifecycle in ~<1KB RAM (excluding wolfCrypt internals)", so I assume their stack usage is low too, because you (the caller) will own and have to allocate all buffers yourself

show 1 reply
nine_kyesterday at 11:44 PM

I used to think that zero alloc = zero malloc, and all stack allocations are of statically known fixed size (you know the max call depth), so you can preallocate your stack area with some confidence, and will never run out of RAM.

The line you point at creates a single local pointer variable which is used in a tight loop; I don't see why won't it stay entirely in a register.

I'm not a real embedded developer though; last time I worked as one I worked on 8-bit devices. Maybe things changed since then.

show 1 reply
wmwraggyesterday at 11:34 PM

My understanding of zero alloc is that there are no heap allocations i.e. use of a form of malloc. At least that has always been my experience, use of the stack is perfectly fine

show 2 replies
adrian_btoday at 9:17 AM

Because this is a library, it presumably allocates nothing in the heap or in static storage.

All data must be allocated in the program invoking procedures from the library, and passed as actual parameters.

You are right about the .text size being dependent on architecture, flags and compiler, but these dependencies may at most double or triple the size. They will certainly not make the size ten times greater. So with a maximum size of 25 kB, I expect that the maximum size will be under 100 kB on any combinations of architecture, flags and compilers.

I do not understand exactly what you mean about "unless it's all rodata". Depending on the architecture, flags and compiler, the constants may be allocated in separate sections, like ".rodata", or they may also be allocated in the same ".text" section with the executable code. The latter choice is typically superior on the CPUs that have relative addressing, like x86_64.

This is what you meant, that it is not clear whether the quoted ".text" size also includes the constants, or not?

I do not think that such a library includes a great amount of constants, so it is likely that adding them or not does not change much the size.

At the line pointed by you, the size of each of the 2 allocated buffers is 64 bytes. The buffer sizes and other parameters that determine the maximum amount of stack usage are defined in "wolfcose.h". It appears that is possible to tune the amount of stack needed, as a tradeoff with the complexity of the messages that can be decoded.

I agree that "Zero dynamic allocation" in the README is not really correct, because they meant "zero allocation in the heap".

Nevertheless, this cannot cause confusions, because any programmer should be aware that a claim of no dynamic allocation of any kind is typically impossible, because almost all functions or procedures must allocate some variables in the stack, with very rare exceptions where there are so few local variables that they may be allocated only inside registers. On x86_64, zero allocation in the stack is completely impossible, because at least the return address must be allocated in the stack.