This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

More on: Help me: how to determine constant value at link time?

Of course I know header file. But my problem is that: I have a lot of C files, who share one Header file, and I made a library. But when I use the library in different projects, I need to modify the parameters, which are defined as MACROs.

So I want to determine these constants' value at linking time. If they are defined as

external code MAX;
external code MIN_VALUE;

Then the source code grows larger, and even worse, some important functions are no longer reentrant-able, because no more registers can be used to pass function paramters.

My library is an operation system based on 51. So you know that reentrant function are import.

I have tries for several months but still fail. It's really a chanllenging problem, and it's every useful for building a library whose parameters can be configured in an ASM file.

Can any one have a solution?

Parents
  • If the value of MAX changes for every project, I'd most likely use a different header file with MAX for every project. If it's a big header with most stuff common to all projects, and you just want to change MAX, then you can pull MAX out into its own header (per project, in some project-specific directory) and have the one big global header #include the per-project version (likely in some sort of global code directory). The library customization parameters would be isolated in their own header, separate from any other. That makes it easier for the user to tweak, too, compared with trying to document something like "go to lines 135-147 of header.h and edit the variables there".

    Another alternative is to define the value for MAX externally, at compile time (on the command line or the DEFINE box in UV2), and not in a header at all. Every project will have its own project/make file, and those can specify different values for max. The one big header doesn't define MAX at all. In that case, I'd recommend some defensive preprocessor code along the lines of:

    #if !defined(MAX)
    #error Must define MAX before compiling header.h
    #endif
    

    just that so when you forget about MAX when setting up the next project, you'll get some sort of hopefully meaningful reminder rather than a syntax error.

    If you really do want the value to be specified as some value in an object module at link time, then I'd think it nearly inevitable that the compiler will generate code to access the address at which the variable lives, which is generally going to be larger code than including the constant value as an immediate operand in the instruction.

    The linker can't really patch the code up, because the code generator has already generated code to do the variable accesses, and it's a bit late for the linker to go back, find all the references to a memory location, and rewrite the instructions so that they use immediate operands that correspond to the value at some offset in some other file.

    One kludge I've seen used to do things like find the end of the actual program code is to define some special segments that locate right after the end of code (for example), and then use that value or the address of a variable defined in that bogus segment to get a link-time result. In this case, you'd have to define the bogus segments for all your parameters, and tell the linker where to put them so that the addresses matched the values you wanted for the parameters. With more than a parameter or two, this technique can easily break down. (What if you need two values of 10, for example? Might not be able to put two segments at the same place....)

Reply
  • If the value of MAX changes for every project, I'd most likely use a different header file with MAX for every project. If it's a big header with most stuff common to all projects, and you just want to change MAX, then you can pull MAX out into its own header (per project, in some project-specific directory) and have the one big global header #include the per-project version (likely in some sort of global code directory). The library customization parameters would be isolated in their own header, separate from any other. That makes it easier for the user to tweak, too, compared with trying to document something like "go to lines 135-147 of header.h and edit the variables there".

    Another alternative is to define the value for MAX externally, at compile time (on the command line or the DEFINE box in UV2), and not in a header at all. Every project will have its own project/make file, and those can specify different values for max. The one big header doesn't define MAX at all. In that case, I'd recommend some defensive preprocessor code along the lines of:

    #if !defined(MAX)
    #error Must define MAX before compiling header.h
    #endif
    

    just that so when you forget about MAX when setting up the next project, you'll get some sort of hopefully meaningful reminder rather than a syntax error.

    If you really do want the value to be specified as some value in an object module at link time, then I'd think it nearly inevitable that the compiler will generate code to access the address at which the variable lives, which is generally going to be larger code than including the constant value as an immediate operand in the instruction.

    The linker can't really patch the code up, because the code generator has already generated code to do the variable accesses, and it's a bit late for the linker to go back, find all the references to a memory location, and rewrite the instructions so that they use immediate operands that correspond to the value at some offset in some other file.

    One kludge I've seen used to do things like find the end of the actual program code is to define some special segments that locate right after the end of code (for example), and then use that value or the address of a variable defined in that bogus segment to get a link-time result. In this case, you'd have to define the bogus segments for all your parameters, and tell the linker where to put them so that the addresses matched the values you wanted for the parameters. With more than a parameter or two, this technique can easily break down. (What if you need two values of 10, for example? Might not be able to put two segments at the same place....)

Children
  • /*----------------------------------------*/

    C51 problem: Incomplete optimization.

    Please see the following code.

    1. Compile this source file, and save the .lst file
    2. comment off "BAD_CODE", and then compare the .lst file
    with the previous one.

    You will find that when compiled with BAD_CODE, the
    statement i<MAX is very lengthy, and more memory is used, even
    worse, the function is no longer reentrant.

    Actually, as we can see from the .lst file, this is due to the
    incomplete optimization of C51, who generated redundant code.

    If this problem is resolved, it can be very useful, because
    the value of a constant can be determined at linking time. For example,
    the parameter of a library can be configured by an ASM file, instead
    of giving the source code to customer and ask him to compile again.

    --------------------------------------------------------------*/

    //comment of this macro to compare the result.
    #define BAD_CODE

    #ifdef BAD_CODE
    //this is defined in another source file
    extern unsigned char MAX[];
    #define MAX (unsigned char)MAX
    #else
    //define MAX as constant, and you will find
    //smaller code size, and better register usage
    #define MAX 3
    #endif



    //when compiled by BAD_CODE, x will be saved in data_group,
    //otherwise, x is in R1-R3,and this function is reentrant-able
    void test(unsigned char i, unsigned char *x)
    {
    if(i>MAX)
    *x = 34;
    else
    *x = 56;
    }

    void main()
    {
    test(1,1);
    }


  • and I made a library. But when I use the library in different projects, I need to modify the parameters, which are defined as MACROs.
    Macros are processed by the COMPILER, and functions in a library are "precompiled". Thus if you change a macro, you must compile again. I build my libraries for every project in the .bat file that generates the code.

    Erik