Hi, I am using the IAR toolchain for our Renesas M16C based project. The device uses a lot of configuration data which are stored within an eeprom. In order to define the placement, I have something like this: eeprom.c: #pragma dataseg="E2PROM_DATA" #define extern /* empty */ #include "eeprom.h" #pragma dataseg=default /* EOF */ and eeprom.h: extern __no_init unsigned char MBUS_exist; extern __no_init char E2_VERSION_TEXT[20]; extern __no_init unsigned char CAN_exists; extern __no_init unsigned char MBUS_exists; /* and so on. */ /* EOF */ I tell the linker to place the E2PROM_DATA segment where the eeprom is mapped into the address space and can use the data from other c sources by including eeprom.h BUT The linker throws away all variables in eeprom.h which are not used anywhere in the projet (there is NO OPTIMIZATION selected!!). This is really bad, since I need a stable address mapping for all configuration data; there might be parameters which may be needed in later software versions; sometimes I build testversions which do not contain all parts. I allways need the variables at the same adresses. I did already asked the IAR support, but did not get a usable answer (they told me to use volatile, but this does not change anything). I see the following approaches: a) define a big struct which contains all variables and put that struct into E2PROM_DATA b) put dummy references to all variables into my project c) define the variables in some assembler source. d) the IAR toolchain allows to put variables at numerically known addresses, I could place every variable at some pre-calculated address a) I would have to change all code referring to (say) E2_VERSION_TEXT to s.E2_VERSION_TEXT (where s is the name of the struct variable). Since my project contains lot of old code, this is not very good. b) ugly, blows up my project with "useless" code (the linker is quite "smart", you have to DO something with a variable or the code is optimized away). c) ugly and dangerous, I have to keep the assembler definitions and c declarations in sync. d) IMHO address calculations should be done by tools, not by programmes due to possible errors. Has anyone some better idea? Greetings Dirk Zabel

IAR linker: too smart
Started by ●May 16, 2006
Reply by ●May 16, 20062006-05-16
"Dirk Zabel" <zabel@riccius-sohn.com> wrote in message news:4cu845F17tattU1@uni-berlin.de...> Hi, > I am using the IAR toolchain for our Renesas M16C based project. The > device uses a lot of configuration data which are stored within an eeprom. > In order to define the placement, I have something like this: > eeprom.c: > #pragma dataseg="E2PROM_DATA" > #define extern /* empty */ > #include "eeprom.h" > #pragma dataseg=default > /* EOF */ > and > eeprom.h: > extern __no_init unsigned char MBUS_exist; > extern __no_init char E2_VERSION_TEXT[20]; > extern __no_init unsigned char CAN_exists; > extern __no_init unsigned char MBUS_exists; > /* and so on. */ > /* EOF */ > > I tell the linker to place the E2PROM_DATA segment where the eeprom is > mapped into the address space and can use the data from other c sources by > including eeprom.h > BUT > The linker throws away all variables in eeprom.h which are not used > anywhere in the projet (there is NO OPTIMIZATION selected!!). This is > really bad, since I need a stable address mapping for all configuration > data; there might be parameters which may be needed in later software > versions; sometimes I build testversions which do not contain all parts. I > allways need the variables at the same adresses. >Instead of defining away extern my instinct would be to put the variable definitions in eeprom.c and leave the declarations in eeprom.h. Then you could initialize the variables in eeprom.c and have a better chance that the linker would leave them alone. I'm assuming that you chose not to do that since you have the __no_init attribute, which, I'm guessing, puts the variables in a non-initialized segment. Maybe that's the problem - have you checked to see what happens without __no_init? Is it because EEPROM can't be initialized? Andrew
Reply by ●May 16, 20062006-05-16
andrew queisser schrieb:> "Dirk Zabel" <zabel@riccius-sohn.com> wrote in message > news:4cu845F17tattU1@uni-berlin.de... > >>Hi, >>I am using the IAR toolchain for our Renesas M16C based project. The >>device uses a lot of configuration data which are stored within an eeprom. >>In order to define the placement, I have something like this: >>eeprom.c: >>#pragma dataseg="E2PROM_DATA" >>#define extern /* empty */ >>#include "eeprom.h" >>#pragma dataseg=default >>/* EOF */ >>and >>eeprom.h: >>extern __no_init unsigned char MBUS_exist; >>extern __no_init char E2_VERSION_TEXT[20]; >>extern __no_init unsigned char CAN_exists; >>extern __no_init unsigned char MBUS_exists; >>/* and so on. */ >>/* EOF */ >> >>I tell the linker to place the E2PROM_DATA segment where the eeprom is >>mapped into the address space and can use the data from other c sources by >>including eeprom.h >>BUT >>The linker throws away all variables in eeprom.h which are not used >>anywhere in the projet (there is NO OPTIMIZATION selected!!). This is >>really bad, since I need a stable address mapping for all configuration >>data; there might be parameters which may be needed in later software >>versions; sometimes I build testversions which do not contain all parts. I >>allways need the variables at the same adresses. >> > > Instead of defining away extern my instinct would be to put the variable > definitions in eeprom.c and leave the declarations in eeprom.h. Then you > could initialize the variables in eeprom.c and have a better chance that the > linker would leave them alone. I'm assuming that you chose not to do that > since you have the __no_init attribute, which, I'm guessing, puts the > variables in a non-initialized segment. > > Maybe that's the problem - have you checked to see what happens without > __no_init? Is it because EEPROM can't be initialized? > > Andrew > >Hi Andrew, the __no_init is required if I use the #pragma dataseg. If I omit it, I get a warning and the variables are placed into the standard data segment. Further, EEPROM variables cannot be initialized by the compiler, linker or loader, as there is a special procedure required to put a value into the non-volatile memory. Of course then #define extern is debatable, but I use this trick to be sure that the definitions and declarations of my variables are always the same. In the case of the IAR toolchain, this is not strictly neccessary, as the compiler emits type informations and the linker complains if there are conflicts. Greetings Dirk
Reply by ●May 16, 20062006-05-16
"Dirk Zabel" <zabel@riccius-sohn.com> schreef in bericht news:4cu845F17tattU1@uni-berlin.de...> Hi, > I am using the IAR toolchain for our Renesas M16C based project. The > device uses a lot of configuration data which are stored within an > eeprom. In order to define the placement, I have something like this: > eeprom.c: > #pragma dataseg="E2PROM_DATA" > #define extern /* empty */ > #include "eeprom.h" > #pragma dataseg=default > /* EOF */ > and > eeprom.h: > extern __no_init unsigned char MBUS_exist; > extern __no_init char E2_VERSION_TEXT[20]; > extern __no_init unsigned char CAN_exists; > extern __no_init unsigned char MBUS_exists; > /* and so on. */ > /* EOF */ > > I tell the linker to place the E2PROM_DATA segment where the eeprom is > mapped into the address space and can use the data from other c sources > by including eeprom.h > BUT > The linker throws away all variables in eeprom.h which are not used > anywhere in the projet (there is NO OPTIMIZATION selected!!). This is > really bad, since I need a stable address mapping for all configuration > data; there might be parameters which may be needed in later software > versions; sometimes I build testversions which do not contain all parts. > I allways need the variables at the same adresses. > > I did already asked the IAR support, but did not get a usable answer > (they told me to use volatile, but this does not change anything). > > I see the following approaches: > a) define a big struct which contains all variables and put that struct > into E2PROM_DATA > b) put dummy references to all variables into my project > c) define the variables in some assembler source. > d) the IAR toolchain allows to put variables at numerically known > addresses, I could place every variable at some pre-calculated address > > a) I would have to change all code referring to (say) E2_VERSION_TEXT to > s.E2_VERSION_TEXT (where s is the name of the struct variable). Since my > project contains lot of old code, this is not very good. > b) ugly, blows up my project with "useless" code (the linker is quite > "smart", you have to DO something with a variable or the code is > optimized away). > c) ugly and dangerous, I have to keep the assembler definitions and c > declarations in sync. > d) IMHO address calculations should be done by tools, not by programmes > due to possible errors. > > Has anyone some better idea?I'd go for a) despite the hassles. While you're at it, you can define minimun, maximum and default values for all your parameters stored in e2prom. Have them initialized with defaults (factory reset), and keep them within defined minimum and maximum allowed values when users change settings etc. Run a sanity check as part of the start up. Things like that can make life a lot easier. Okay, you need to have the space for such extras, but if you can afford it... -- Thanks, Frank. (remove 'q' and '.invalid' when replying by email)
Reply by ●May 16, 20062006-05-16
"Frank Bemelman" <f.bemelmanq@xs4all.invalid.nl> wrote in message news:446a31d9$0$9354$e4fe514c@dreader14.news.xs4all.nl...> "Dirk Zabel" <zabel@riccius-sohn.com> schreef in bericht > news:4cu845F17tattU1@uni-berlin.de... >> Hi, >> I am using the IAR toolchain for our Renesas M16C based project. The >> device uses a lot of configuration data which are stored within an >> eeprom. In order to define the placement, I have something like this: >> eeprom.c: >> #pragma dataseg="E2PROM_DATA" >> #define extern /* empty */ >> #include "eeprom.h" >> #pragma dataseg=default >> /* EOF */ >> and >> eeprom.h: >> extern __no_init unsigned char MBUS_exist; >> extern __no_init char E2_VERSION_TEXT[20]; >> extern __no_init unsigned char CAN_exists; >> extern __no_init unsigned char MBUS_exists; >> /* and so on. */ >> /* EOF */ >> >> I tell the linker to place the E2PROM_DATA segment where the eeprom is >> mapped into the address space and can use the data from other c sources >> by including eeprom.h >> BUT >> The linker throws away all variables in eeprom.h which are not used >> anywhere in the projet (there is NO OPTIMIZATION selected!!). This is >> really bad, since I need a stable address mapping for all configuration >> data; there might be parameters which may be needed in later software >> versions; sometimes I build testversions which do not contain all parts. >> I allways need the variables at the same adresses. >> >> I did already asked the IAR support, but did not get a usable answer >> (they told me to use volatile, but this does not change anything). >> >> I see the following approaches: >> a) define a big struct which contains all variables and put that struct >> into E2PROM_DATA >> b) put dummy references to all variables into my project >> c) define the variables in some assembler source. >> d) the IAR toolchain allows to put variables at numerically known >> addresses, I could place every variable at some pre-calculated address >> >> a) I would have to change all code referring to (say) E2_VERSION_TEXT to >> s.E2_VERSION_TEXT (where s is the name of the struct variable). Since my >> project contains lot of old code, this is not very good. >> b) ugly, blows up my project with "useless" code (the linker is quite >> "smart", you have to DO something with a variable or the code is >> optimized away). >> c) ugly and dangerous, I have to keep the assembler definitions and c >> declarations in sync. >> d) IMHO address calculations should be done by tools, not by programmes >> due to possible errors. >> >> Has anyone some better idea? > > I'd go for a) despite the hassles. While you're at it, you can > define minimun, maximum and default values for all your parameters > stored in e2prom. Have them initialized with defaults (factory reset), > and keep them within defined minimum and maximum allowed values when > users change settings etc. Run a sanity check as part of the start up. > Things like that can make life a lot easier. Okay, you need to have > the space for such extras, but if you can afford it... >yes, and use the #define to overcome the problem of old code (if it's really such a problem) e.g #define E2_VERSION_TEXT (s.E2_VERSION_TEXT)
Reply by ●May 16, 20062006-05-16
- schrieb:> "Frank Bemelman" <f.bemelmanq@xs4all.invalid.nl> wrote in message > news:446a31d9$0$9354$e4fe514c@dreader14.news.xs4all.nl... > >>"Dirk Zabel" <zabel@riccius-sohn.com> schreef in bericht >>news:4cu845F17tattU1@uni-berlin.de... >> >>>Hi, >>>I am using the IAR toolchain for our Renesas M16C based project. The >>>device uses a lot of configuration data which are stored within an >>>eeprom. In order to define the placement, I have something like this: >>>eeprom.c: >>>#pragma dataseg="E2PROM_DATA" >>>#define extern /* empty */ >>>#include "eeprom.h" >>>#pragma dataseg=default >>>/* EOF */ >>>and >>>eeprom.h: >>>extern __no_init unsigned char MBUS_exist; >>>extern __no_init char E2_VERSION_TEXT[20]; >>>extern __no_init unsigned char CAN_exists; >>>extern __no_init unsigned char MBUS_exists; >>>/* and so on. */ >>>/* EOF */ >>> >>>I tell the linker to place the E2PROM_DATA segment where the eeprom is >>>mapped into the address space and can use the data from other c sources >>>by including eeprom.h >>>BUT >>>The linker throws away all variables in eeprom.h which are not used >>>anywhere in the projet (there is NO OPTIMIZATION selected!!). This is >>>really bad, since I need a stable address mapping for all configuration >>>data; there might be parameters which may be needed in later software >>>versions; sometimes I build testversions which do not contain all parts. >>>I allways need the variables at the same adresses. >>> >>>I did already asked the IAR support, but did not get a usable answer >>>(they told me to use volatile, but this does not change anything). >>> >>>I see the following approaches: >>>a) define a big struct which contains all variables and put that struct >>>into E2PROM_DATA >>>b) put dummy references to all variables into my project >>>c) define the variables in some assembler source. >>>d) the IAR toolchain allows to put variables at numerically known >>>addresses, I could place every variable at some pre-calculated address >>> >>>a) I would have to change all code referring to (say) E2_VERSION_TEXT to >>>s.E2_VERSION_TEXT (where s is the name of the struct variable). Since my >>>project contains lot of old code, this is not very good. >>>b) ugly, blows up my project with "useless" code (the linker is quite >>>"smart", you have to DO something with a variable or the code is >>>optimized away). >>>c) ugly and dangerous, I have to keep the assembler definitions and c >>>declarations in sync. >>>d) IMHO address calculations should be done by tools, not by programmes >>>due to possible errors. >>> >>>Has anyone some better idea? >> >>I'd go for a) despite the hassles. While you're at it, you can >>define minimun, maximum and default values for all your parameters >>stored in e2prom. Have them initialized with defaults (factory reset), >>and keep them within defined minimum and maximum allowed values when >>users change settings etc. Run a sanity check as part of the start up. >>Things like that can make life a lot easier. Okay, you need to have >>the space for such extras, but if you can afford it...Well, yes, but in my project there is already another software device taking care of user interface, limits and default values.>> > > > yes, and use the #define to overcome the problem of old code (if it's really > such a problem) > > e.g > > #define E2_VERSION_TEXT (s.E2_VERSION_TEXT) > >Thanks for all your comments! I think, this looks best so far. Quite a lot of definitions (hope there will be no symbol table overflow in the preprocessor), but with todays memory sizes it should not be a problem. And all the defintions can be put into one file (eeprom.h), this is nice. But why on earth his this linke no option to switch off unwanted optimization? Greetings Dirk
Reply by ●May 16, 20062006-05-16
Dirk Zabel wrote:> Hi, > I am using the IAR toolchain for our Renesas M16C based project. The > device uses a lot of configuration data which are stored within an > eeprom. In order to define the placement, I have something like this: > eeprom.c: > #pragma dataseg="E2PROM_DATA" > #define extern /* empty */ > #include "eeprom.h" > #pragma dataseg=default > /* EOF */ > and > eeprom.h: > extern __no_init unsigned char MBUS_exist; > extern __no_init char E2_VERSION_TEXT[20]; > extern __no_init unsigned char CAN_exists; > extern __no_init unsigned char MBUS_exists; > /* and so on. */ > /* EOF */ > > I tell the linker to place the E2PROM_DATA segment where the eeprom is > mapped into the address space and can use the data from other c sources > by including eeprom.h > BUT > The linker throws away all variables in eeprom.h which are not used > anywhere in the projet (there is NO OPTIMIZATION selected!!). This is > really bad, since I need a stable address mapping for all configuration > data; there might be parameters which may be needed in later software > versions; sometimes I build testversions which do not contain all parts. > I allways need the variables at the same adresses. > > I did already asked the IAR support, but did not get a usable answer > (they told me to use volatile, but this does not change anything). > > I see the following approaches: > a) define a big struct which contains all variables and put that struct > into E2PROM_DATA > b) put dummy references to all variables into my project > c) define the variables in some assembler source. > d) the IAR toolchain allows to put variables at numerically known > addresses, I could place every variable at some pre-calculated address > > a) I would have to change all code referring to (say) E2_VERSION_TEXT to > s.E2_VERSION_TEXT (where s is the name of the struct variable). Since my > project contains lot of old code, this is not very good. > b) ugly, blows up my project with "useless" code (the linker is quite > "smart", you have to DO something with a variable or the code is > optimized away). > c) ugly and dangerous, I have to keep the assembler definitions and c > declarations in sync. > d) IMHO address calculations should be done by tools, not by programmes > due to possible errors. > > Has anyone some better idea?Is the problem is in getting the EEPROM values into HEX, or does the linker 'reshuffle' the deck for you, by removing unused data ? If the latter, then you could just SUM all EE variables into one expression/load - that way, you get around this weakness, as the variables are references eg DummyLoad = VERY+LONG+SUM+OF+ALL+EE+NAMES If you are lucky, and place that into a never called function, then then linker might throw that away (unused), but not the names :) -jg
Reply by ●May 16, 20062006-05-16
Dirk Zabel wrote:> I did already asked the IAR support, but did not get a usable answer > (they told me to use volatile, but this does not change anything).I find it hard to believe that you asked the right question. I've seen IAR support answer exactly this question, when it was asked the MSP430 ml.> Has anyone some better idea?Use the __root keyword, this is what it's for. The linker does garbage collection, including only those things that are actually used, and __root adds a "root" to the gc. A root is a thing that you declare to be needed even if the gc can't see it being used. It's documented in the manual in the same place that __no_init is. Clifford Heath.
Reply by ●May 17, 20062006-05-17
Clifford Heath schrieb:> Dirk Zabel wrote: > >> I did already asked the IAR support, but did not get a usable answer >> (they told me to use volatile, but this does not change anything). > > > I find it hard to believe that you asked the right question. I've > seen IAR support answer exactly this question, when it was asked > the MSP430 ml. > >> Has anyone some better idea? > > > Use the __root keyword, this is what it's for. The linker does > garbage collection, including only those things that are actually > used, and __root adds a "root" to the gc. A root is a thing that > you declare to be needed even if the gc can't see it being used. > > It's documented in the manual in the same place that __no_init is. > > Clifford Heath.Thanks to Clifford Heath, the __root keyword helped. I should have seen this, as it is documented in the compiler reference manual. :-( The question I asked was "is there any way to prevent the linker from this optimization". The answer was "no, there isn't one (only -q for version 4.10 of the ARM compiler)". Maybe I should have asked for a compiler (not linker) setting, but if I had known that the linker options are the wrong place to look I should have found the answer by myself. Anyway, thank you very much! Greetings Dirk
Reply by ●May 17, 20062006-05-17
Dirk Zabel wrote:> Hi, > I am using the IAR toolchain for our Renesas M16C based project. The > device uses a lot of configuration data which are stored within an > eeprom. In order to define the placement, I have something like this: > eeprom.c: > #pragma dataseg="E2PROM_DATA" > #define extern /* empty */ > #include "eeprom.h" > #pragma dataseg=default > /* EOF */ > and > eeprom.h: > extern __no_init unsigned char MBUS_exist; > extern __no_init char E2_VERSION_TEXT[20]; > extern __no_init unsigned char CAN_exists; > extern __no_init unsigned char MBUS_exists; > /* and so on. */ > /* EOF */ >Any code which uses the preprocessor to redefine a keyword like "extern" is incorrect code. It doesn't matter whether it works or not - it's still so bad that any experienced reviewer would reject it outright.> I tell the linker to place the E2PROM_DATA segment where the eeprom is > mapped into the address space and can use the data from other c sources > by including eeprom.h > BUT > The linker throws away all variables in eeprom.h which are not used > anywhere in the projet (there is NO OPTIMIZATION selected!!). This is > really bad, since I need a stable address mapping for all configuration > data; there might be parameters which may be needed in later software > versions; sometimes I build testversions which do not contain all parts. > I allways need the variables at the same adresses. > > I did already asked the IAR support, but did not get a usable answer > (they told me to use volatile, but this does not change anything). >IAR support are not famed for being helpful - on the other hand, their tools are well known for making correct and efficient code. The compiler (and linker) is doing exactly the right thing - if you declare variables that are never used, then the compiler and/or linker is free to remove them - they have no effect on the running of your program. You might think that the declarations have an effect on the addressing in eeprom - but that is not true. The order you declare or define data has no defined effect on the order in memory. For many targets, compilers will re-order the data for better alignment or padding. So even if you manage to persuade the tools to keep the unused data, you are getting a false sense of security - a new compilation could re-arrange the data. The easiest way to get the effect you are looking for is to define a single structure for all the eeprom-based data, and ensure that it is linked to one specific address (solution "a" below). If you want to access struct members without having to add "s." in front of them, you could use #defines to avoid it (although it is almost certainly best to correct the old code rather than add hacks around it). Solution (b) would not work (as explained above). Solution (c) is perfectly reasonable (although more effort than (a)), and solution (d) is again possible, but lots of effort to do well.> I see the following approaches: > a) define a big struct which contains all variables and put that struct > into E2PROM_DATA > b) put dummy references to all variables into my project > c) define the variables in some assembler source. > d) the IAR toolchain allows to put variables at numerically known > addresses, I could place every variable at some pre-calculated address > > a) I would have to change all code referring to (say) E2_VERSION_TEXT to > s.E2_VERSION_TEXT (where s is the name of the struct variable). Since my > project contains lot of old code, this is not very good. > b) ugly, blows up my project with "useless" code (the linker is quite > "smart", you have to DO something with a variable or the code is > optimized away). > c) ugly and dangerous, I have to keep the assembler definitions and c > declarations in sync. > d) IMHO address calculations should be done by tools, not by programmes > due to possible errors. > > Has anyone some better idea? > > > Greetings > Dirk Zabel >
