4

In a bare metal C/C++ project, I use gcc-arm-embedded (currently the most recent 4.9-2015-q2).

For some reasons, I have to avoid using some functions, like some of stdio et cetera (don't want to use retargeting or semihosting).

Further, I use FreeRtos with heap_4.c and had e.g. malloc() redirected directly to pvPortMalloc() like this:

void* malloc(size_t s) {
    return pvPortMalloc(s);
}

Therefore, I don't want to have any parts of the toolchain's heap management code within my binary.

Now, there are some situations, as were a developer of my team means to use e.g. printf() which indirectly references _malloc_r() (and some more) and it's actually quite hard to find out where it's referenced from and so where to fix.

(The use printf() is just an example here. In my project, I have custom implementation of printf() which prints directly to uart without using stdio. But there are other cases, e.g. type info demangeling, …)

Currently, I have the situation that my project (which consists of about 200 c and c++ source files) compiles well without referencing _malloc_r() in any way - as long as I build with gcc 4.8.

But when building with gcc 4.9, I see unwanted references to _malloc_r and some more.

Might there be command line tool to analyze my elf file for finding out where specific functions are referenced from?

Edit 2015-07-20:

  • Finally, I'd solved my underlying problem, that I need to build my whole project with gcc 4.9 without having references to _malloc_r inside of my code.
  • Some of the references I'd found by applying this answer.
  • Further I find out, that there is a __gnu_cxx::__snprintf_lite() which references the full blown of iostream which I don't want in my code. This __gnu_cxx::__snprintf_lite() is used by some exceptions of the gcc stl implementation (e.g. referenced by __throw_out_of_range_fmt()). (Yep, my code uses std::map). My way to get rid of iostream was to simply provide my own __gnu_cxx::__snprintf_lite() like this (having my own small footprint vsnprintf):

    namespace __gnu_cxx {
        int __snprintf_lite(char* buf, size_t bufsize, const char* fmt, va_list ap) {
            return vsnprintf(buf, bufsize, fmt, ap);
        }
    }
    

    This can be checked by viewing the gcc-4.9 library sources (e.g. src/gcc/libstdc++-v3/src/c++11/snprintf_lite.cc).

Community
  • 1
  • 1
Joe
  • 3,090
  • 6
  • 37
  • 55
  • Perhaps the linker can tell you, if you can prevent inclusion of a definition of the relevant function(s). – Cheers and hth. - Alf Jun 27 '15 at 12:23
  • Unfortulately, I don't know the names of all functions which could directly or indirectly results in references of e.g. `_malloc_r`. – Joe Jun 27 '15 at 12:27
  • You could use `objdump -d` to disassemble all executable sections and redirect the output to a file and search for `_malloc_r` in it with a text editor. – 4566976 Jun 27 '15 at 12:27
  • Take a look to Hooks-for-Malloc http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html – frhack Jun 27 '15 at 12:32
  • LD_PRELOAD http://stackoverflow.com/questions/2948448/gcc-how-to-block-system-calls-within-a-program – frhack Jun 27 '15 at 12:42

3 Answers3

2

Peraphs using a custom malloc.h where you can undef or redefine _malloc_r

Something similar to:

extern _PTR malloc _PARAMS ((size_t));
#ifdef __CYGWIN__
#undef _malloc_r
#define _malloc_r(r, s) malloc (s)
#else
extern _PTR _malloc_r _PARAMS ((struct _reent *, size_t));
#endif

Take a look to Hooks-for-Malloc too

The GNU C Library lets you modify the behavior of malloc, realloc, and free by specifying appropriate hook functions. You can use these hooks to help you debug programs that use dynamic memory allocation, for example.

The hook variables are declared in malloc.h.

Another hint is using LD_PRELOAD What is the LD_PRELOAD trick?

Community
  • 1
  • 1
frhack
  • 4,862
  • 2
  • 28
  • 25
  • Yep, IMHO there is no way for `LD_PRELOAD` on bare metal. – Joe Jun 27 '15 at 13:41
  • About malloc hooks: `_malloc_c()` is just an example. I'd somtimes also observed unwanted references to e.g. `_write()` or some other (not stdio related) unwanted functions. – Joe Jun 27 '15 at 13:44
  • `-flto` won't help because the unwanted `_malloc_r()` is really referenced (indirectly e.g. via `sprintf` or something else) and I have to find the guilty code location in my sources. – Joe Jun 27 '15 at 22:03
2

I am not sure, whether I understood you correctly, but it seems you want to avoid using some specific functions in your project. How about simply poisoning the function identifiers?

This code fails to compile (intentionally) for printf:

#define printf FORBIDDEN

int main(int argc, char *argv[]) {
  printf("Test");
}

with the following error:

Untitled.cpp:11:3: error: no matching function for call to 'FORBIDDEN'
  printf("Test");
  ^~~~~~
Untitled.cpp:3:16: note: expanded from macro 'printf'
#define printf FORBIDDEN
               ^~~~~~~~~

So the order of declaration and redefinition does not matter. You do not need to know all functions that call forbidden functions:

#define printf FORBIDDEN

// this in included file:
void otherfunc() {
  printf("I fail.");
}
// eof included file

int main(int argc, char *argv[]) {
  otherfunc();
}
Kuba Wyrostek
  • 6,163
  • 1
  • 22
  • 40
  • This approch results in that I have to maintain a blacklist of all forbidden functions. Further, it poisens all `printf` keywords in code, even such a possible allowed `OutStream::printf` implementation. – Joe Jun 27 '15 at 13:39
2

This is an example for finding out the references to _exit in a statically compiled program:

/* hello.c */
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    write(1, "Hello\n", 6);
    _exit(0);
}

Compile it:

$ gcc hello.c -static -g

Find out the address of _exit:

$ nm a.out | grep " _exit"
000000000040f760 T _exit

Disassemble with objdump -d -j .text, grep for the address of _exit, cut the address out of the line and pipe it to addr2line:

$ objdump -d -j .text a.out | grep 40f760 | cut -c 1-8 | addr2line -e a.out -f
oom
dl-tls.o:?
main
/home/m/hello.c:8
__run_exit_handlers
??:?
??
??:0
_Exit
??:?
_dl_non_dynamic_init
??:?
abort
??:?
do_lookup_x
dl-lookup.o:?
_dl_relocate_object
??:?
_dl_signal_error
??:?
dl_open_worker
dl-open.o:?
_dl_close_worker.part.0
dl-close.o:?
_dl_start_profile
??:?

The result is:

Functions oom, main, __run_exit_handlers, ... do reference the function _exit.

4566976
  • 2,419
  • 1
  • 10
  • 14
  • I think, this leads to the right direction. Could you tell the reason of the `oom` argument of `addr2line`? – Joe Jun 28 '15 at 11:49
  • @Joe `oom` is part of the output of `addr2line`. It is a `static` [function](http://code.metager.de/source/xref/gnu/glibc/elf/dl-tls.c) (out of memory) in the dl library which calls `_exit`. – 4566976 Jun 28 '15 at 13:37
  • Well, using this approch, I find out that `_malloc_r` is referenced by `__ssprint_r` and `__submore`; `__ssprint_r` itself is referenced by something named `St`?! `__submore` is referenced by `_sungetc_r` which also referenced by `St`. At this point, I stuck on trying to follow the referencing chain up to my own code. – Joe Jun 28 '15 at 15:23
  • Following the address of that `St` by manually checking the `objdump` output, I see that it is referenced by `__ssvfscanf_r` which is referenced by `sscanf` which is referenced by `_ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKPi` (`void std::__convert_to_v(char const*, long double&, std::_Ios_Iostate&, int* const&)`) which leads me to some iostream related template stuff. – Joe Jun 28 '15 at 15:59
  • After researching my code for a while, I find out that there are some different indirect refences to `_malloc_r` (in my concrete case). Some of them I'd found using this approach (e.g. `localtime()` and `mktime()` are referencing `_malloc_r` indirectly (via `mktime` → `_tzset_unlocked` → `_tzset_unlocked_r` → `_malloc_r`) when building with gcc-arm 4.9); another hit, I'd described within my question – Joe Jul 02 '15 at 16:14