4
\$\begingroup\$

I'm porting standard C library for bare metal "OS" (ARM Cortex-M4, ARM GCC). I want to have functions like strlen, sprintf, (and memory allocator, maybe), etc.

I've ported PDCLib and Newlib. Newlib isn't lightweight (and try to implement files operations, etc.). PDCLib is not in active development.

So, I want Microlib exactly. But it's not for GCC and closed source.

Are there some alternatives for this? And are there some "bare metal subsets" of standard C library?

\$\endgroup\$
  • \$\begingroup\$ I had good results with newlib-nano. If you want smaller I'm afraid youl have to go the Keil way and pay the big bucks. \$\endgroup\$ – Paulo Soares Nov 14 '16 at 10:03
10
\$\begingroup\$

When I want a truly light-weight (and/or one that is thread-safe) library I usually write my own. It's not hard to do.

Since you discuss a "memory allocator," let me suggest that a malloc()/free pair is trivial to write -- perhaps a few dozen lines:

#define STATUSFREE 0
#define STATUSUSED 1
struct tag {
    struct tag * next;
    int status;
};
struct tag * heap;
void free( void * p ) {
    struct tag * ptag= ((struct tag *)p) - 1;
        ptag->status= STATUSFREE;
}
void * malloc( size_t s ) {
    struct tag *ptag, *pnext;
        for ( ptag= heap; ptag != NULL; ptag= ptag->next )
            if (ptag->status == STATUSFREE) {
                for ( pnext= ptag->next; pnext->status == STATUSFREE; pnext= pnext->next )
                    ;
                if ( s <= (size_t) (((char *) pnext) - (char *) (ptag+1)) ) {
                    if ( s <= (size_t) (((char *) pnext) - (char *) (ptag+2)) ) {
                        ptag->next= (struct tag *) (s + (char *) (ptag+1));
                        ptag->next->status= STATUSFREE;
                        ptag->next->next= pnext;
                    } else
                        ptag->next= pnext;
                    ptag->status= STATUSUSED;
                    return ptag+1;
                }
                ptag->next= pnext;
            }
    return NULL;
}

You initialize it the following way. First, set up a fixed block of memory using a standard array allocation like this:

static char mspace[1000];

That can be placed into some module you write. It should be allocated as static lifetime, of course.

Then, somewhere else (like in main()), you do the following:

((struct tag *) &mspace[0])->status= STATUSFREE;
((struct tag *) &mspace[0])->next= &((struct tag *) &mspace[sizeof(mspace)])[-1];
((struct tag *) &mspace[sizeof(mspace)])[-1].status= STATUSUSED;
((struct tag *) &mspace[sizeof(mspace)])[-1].next= NULL;
heap= (struct tag *) &mspace[0];

It's very fast and very easy.

strlen() is, of course, much easier and you can find all manner of implementation on the web for that.

The rest? I'd recommend that you write those, too. A very, very helpful book here is P. J. Plauger's (one of the founders of Whitesmiths LTD -- compiler company) "The Standard C Library." Just get a copy. You won't be sorry. It covers things like sprintf() for you, which is much more complicated and may involve treating with floating point values when converting for output. (When you re-create sprintf(), you will haul in lots of code as a result of that -- but it's just needed if you want such a powerful library function.)

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks very much! Do you have repositories (because well-maintained code with tests is good, too :-))? \$\endgroup\$ – Kuraga Nov 14 '16 at 19:32
  • 3
    \$\begingroup\$ @Kuraga Since I have been doing embedded work for decades, including writing the entire operating system code (which I can often now write from scratch to working shape in two days or less on any given system), I have lots of source code from various projects that I retain here. When I need something, I search the projects and extract the bits I need. Each library is custom to the project, though. The reason is partly because some work I do is medical and EVERY LINE of code has to be thoroughly vetted. Tossing in unused code is "bad." I almost never use the C libraries from compilers. \$\endgroup\$ – jonk Nov 14 '16 at 19:37
  • 1
    \$\begingroup\$ @Kuraga Code I write is still operating after 30 years in some cases. Completed applications I write just work. I've received a call from one client who'd been using my software with tens of thousands of their own customers for 20 years, calling me to tell me that there hasn't been a single confirmed bug found in my code in all that time. But I just haven't had the time to organize and document my code for others to use well. That takes a LOT of additional effort AND thinking time to make sure I pass along all that would be needed for others to use it. \$\endgroup\$ – jonk Nov 14 '16 at 19:43
  • 1
    \$\begingroup\$ Why would you even bother with malloc, since this is about bare metal embedded systems? malloc doesn't make any sense to use, see this. \$\endgroup\$ – Lundin Nov 15 '16 at 8:26
  • 2
    \$\begingroup\$ @Lundin I interpreted "memory allocator" as suggestive. \$\endgroup\$ – jonk Nov 15 '16 at 8:34
0
\$\begingroup\$

You should take a look at musl.

It's lightweight and open source, and it is intended for embedded application.
I don't know if this satisfy exactly your requirements.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for reply! No, its Linux-dependent but not bare metal. \$\endgroup\$ – Kuraga Nov 14 '16 at 11:33
  • \$\begingroup\$ @Kuraga Sorry... \$\endgroup\$ – Antonio Nov 14 '16 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.