This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS470 links function to constant



Recently I had an issue where a function was apparently linking to a constant, causing an abort when executed. The problem was introduced because of bad code, but it brought up questions about the linker.

There was a macro with the same name as a constant structure; The file that was trying to use the macro didn't include the header where it was defined. This implicitly defined the function, which is to be expected. What was unexpected was that it linked to a constant, which was not a function or pointer-to a function. I am using version 4.6 of the TMS470 compiler. Here's a summary of the offending code:

Structure defined elsewhere:

typedef struct {
uint8_t *addr; 
uint8_t first_bit;
uint8_t last_bit;
}Byte_Bit_Fld_T;

Header A:
extern const Byte_Bit_Fld_T Not_A_Function;

C File A:
const Byte_Bit_Fld_T Not_A_Function =
{(uint8_t *) &var[6] /*uint8_t array*/, 1, 1 };

Header B (no longer included):

extern some_structure

#define Not_A_Function() \
( some_structure.some_member )

C File B:

//#include "header_B"  header with macro is no longer included

if ( ( 0 != SOME_OTHER_MACRO() ) && ( !some_bool || !Not_A_Function() )

// Not_A_Function is implicitly declared and gets linked to the constant from header A

I would expect this code to cause a type error, since Not_A_Function is not a function or pointer-to a function, and there's no cast. Otherwise I would expect there to be undefined symbols and a link error. Is there any chance this could be compiler error, or are my assumptions about the linker wrong? Normally, a compiler error is one of the last things I look for, but they do happen. I'd really like to know what's going on here, even though this can be prevented by writing better code.

  • This is what you get, in C, for not having a header flle for each C file, where each C file has to include its own header.

    C++ would catch this with its name-mangling; nowadays I believe all C code (at least all new C code) should be compiled in C++ instead of C, to catch exactly this.

    Your call from C file B resolves NOT to the header A, but rather the C file A.

    C compilers were designed in the stone age, where linkers were basically like assembly language linkers. You give it a name, it resolves to a location; linkers were not even SUPPOSED to do type checking back then (the correct header discipline, mentioned above, generally solves this issue). Because of overloading C++ linkers HAD to do type checking, with the benefit of catching the above problem.

    Try doing the same think in C++ but putting "extern "C"" around all the relevant decls and defns and you'll run into exactly the same problem as above.

    There is neither a compiler bug nor a linker bug here -- these tools were designed (and specified) to work exactly this way.

  • It's true that the TI compiler, like many compilers, doesn't normally do type checking between modules.  However, if you enable optimization level 4 (-o4), you will get type checking of static-scoped objects (functions and global variables), which might help in this case.

  • Thanks for the response; I never seriously thought a compiler bug was likely, but I was unable to reproduce this in the original program (kept getting errors). For some reason I didn't even try using the function without including the header (guess I like my programs to link correctly). Now I have a good example of the behavior, which I will include in this reply in case it helps anyone.

    I think the key here is that, without the header, the linker performs no type checking. It just sees a symbol in the table, because the function has external linkage. Actually, both files in the original program had matching headers; the problem was that the programmer allowed an implicit function declaration into the final code (this was caused by not including the appropriate header from the other module). This warning should be enforced like an error (in my opinion), either manually by the programmer checking diagnostic messages, or through compiler options (the TMS470 v4.6 compiler, like many C89 compilers, produces no warnings for implicit functions). I was unaware that no type checking would occur, so I appreciate being corrected on that assumption (the worst thing would be to carry on working from bad assumptions). Here's a revised example:

    // -------- Start of "main.c" --------
    /* 
       Type check will be performed if the header not_a_function.h is included,
       resulting in an error
    Since no header is included, the linker will look in the symbol table, and find not_a_function. Functions have external linkage by default, so this will link, because no type check is performed when linking to separate C file */ void main( void ) { not_a_function(); } // -------- Start of "not_a_function.h" -------- extern const int not_a_function; // -------- Start of "not_a_function.c" -------- #include "not_a_function.h" const int not_a_function;

    If you then build:

    $(CC) -c main.c
    $(CC) -c not_a_function.c
    $(CC)  -z main.obj not_a_function.obj -e=_main -o fin
    <Linking>

    It builds with no warnings. If you examine the asm, you can see that there is a branch to the const symbol. I might not be a C expert, but I don't consider myself a novice either, so this was a humbling experience. Thank you very much, I learned something today!

  • Thank you for the response, Archaeologist! Neither this, nor compiling with the C++ compiler would be practical for this project, but this thread did help clear up the misunderstanding. If the original code had been more disciplined, this wouldn't have been an issue. It was especially tough for me to debug, because the style(s) that I have used in the past would not have allowed this error to occur, so I didn't really need to worry about it. Thanks again.

  • Murph612 said:
    the problem was that the programmer allowed an implicit function declaration into the final code (this was caused by not including the appropriate header from the other module). This warning should be enforced like an error (in my opinion), either manually by the programmer checking diagnostic messages, or through compiler options (the TMS470 v4.6 compiler, like many C89 compilers, produces no warnings for implicit functions)

    You probably want to use the -pdse225 option in your program to make implicit function declarations errors.