简体   繁体   中英

IAR Compiler: using struct with function pointers, map file shows all the function declared in struct irrespective of function used or not

I have a struct with 10 function pointers. A global instance of the struct is initialized wit function pointers pointing to local functions. In my application, using any one or more of the function references causes linker to include all 10 functions in the map file.

In order to save memory, I need linker to include onle those functions that used in the application. Not all the functions referenced in the struct.

Struct in file r_adc_api.h (from Manufacturer)

typedef struct st_adc_api
    {
        ssp_err_t (* open)(adc_ctrl_t * const p_ctrl,  adc_cfg_t const * const      p_cfg);
        ssp_err_t (* scanCfg)(adc_ctrl_t * const p_ctrl,  adc_channel_cfg_t const * const p_channel_cfg);
        ssp_err_t (* scanStart)(adc_ctrl_t * const p_ctrl);
        ssp_err_t (* scanStop)(adc_ctrl_t * const p_ctrl);
        ssp_err_t (* scanStatusGet)(adc_ctrl_t * const p_ctrl);
        ssp_err_t (* read)(adc_ctrl_t  * const p_ctrl, adc_register_t const  reg_id,  adc_data_size_t * const p_data);
        ssp_err_t (* sampleStateCountSet)(adc_ctrl_t * const p_ctrl,  adc_sample_state_t  * p_sample);
        ssp_err_t (* close)(adc_ctrl_t * const p_ctrl);
        ssp_err_t (* infoGet) (adc_ctrl_t * const p_ctrl, adc_info_t * const p_adc_info);
        ssp_err_t (* versionGet)(ssp_version_t * const p_version);
    } adc_api_t;

**Header r_adc.h ** (from Manufacturer)

extern const adc_api_t g_adc_on_adc;

Assignment and function definitions is in file r_adc.c (from Manufacturer)

const adc_api_t g_adc_on_adc =
{
    .open                   = R_ADC_Open,
    .scanCfg                = R_ADC_ScanConfigure,
    .infoGet                = R_ADC_InfoGet,
    .scanStart              = R_ADC_ScanStart,
    .scanStop               = R_ADC_ScanStop,
    .scanStatusGet          = R_ADC_CheckScanDone,
    .sampleStateCountSet    = R_ADC_SetSampleStateCount,
    .read                   = R_ADC_Read,
    .close                  = R_ADC_Close,
    .versionGet             = R_ADC_VersionGet
};

and ## Function Definitions ##

** MAP File ** MAP file

In my Application, if i use adc_on_g_adc.open(...); linker pulls all 10 symbols to the map file instead of just pulling R_ADC_Open();

What might be causing .map file to pull all the functions from the struct even if one function is called?

Edit: Putting all these together in one single file gives map file I need. IAR compiler omits unused functions. Just doesn't work when I use multiple header and source.

If you fill up the structure with function pointers, the functions have been "used" so far as the linker is concerned.

Think about it in terms of what the linker is supposed to replace R_ADC_ScanConfigure with. It can't choose to set g_adc_on_adc.scanCfg to NULL, can it? It doesn't know that the object code doesn't actually call g_adc_on_adc.scanCfg .

Basically, it's only option is to include R_ADC_ScanConfigure in the output.

However, if instead of assigning R_ADC_ScanConfigure in the structure you set g_adc_on_adc.scanCfg to NULL, the linker would then be able omit R_ADC_ScanConfigure from the output.

const adc_api_t g_adc_on_adc =
{
    .open                   = R_ADC_Open,
    .scanCfg                = NULL,
    .infoGet                = R_ADC_InfoGet,
    .scanStart              = R_ADC_ScanStart,
    .scanStop               = R_ADC_ScanStop,
    .scanStatusGet          = R_ADC_CheckScanDone,
    .sampleStateCountSet    = R_ADC_SetSampleStateCount,
    .read                   = R_ADC_Read,
    .close                  = R_ADC_Close,
    .versionGet             = R_ADC_VersionGet
};

Of course, if your code then did end up calling g_adc_on_adc.scanCfg you'd be trying to run code at address 0 (probably), which would be a very bad thing indeed. You could make .scanCfg point to a function that simply prints up a nasty error message on your console / down your serial port / whatever so that at least you know something has gone wrong.

The feature you are looking for is called virtual function elimination and does just what you want but for only for virtual functions in C++.

In your code all the compiler sees is a structure initialized with some pointers to functions. If this structure is global or somehow exported from this module the compiler must assume that all the initialized parts of the structure are used.

When the linker gets hold of all this it sees a reference to the structure, that's all. There is no information there to tell the linker what part of the structure is used.

When you put everything in the same module the compiler can find out what function you actually reference and go there directly, this will leave the structure without references meaning it can be thrown away and with it all the references to the other functions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM