We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello, I am a student from germany and I am working on a project with KeilC an uVison. I have a strange problem. - I get some C-code for a 8051 compatible - this code has extern linker files - the current code compiles without errors - after compiling I see some size-values for DATA,XDATA,PDATA - if i want to shrink the code by deleting or uncommenting some lines the linker throws errors, because the size of data exceed the restrictions by the linker file.
I do not understand, why the code size increases if I shrink the code? Can some one explain me this issue?
Thank you for help, Regard Chris
The most common reason is that you uncomment the last call to a function, without removing the code for the now unused function.
Note that in the C51 world, the linker often does a lot more than just linking. It can also perform the last steps of code optimization, and one of the optimizations for 8051 processors is to convert local variables and call parameters into global variables. But that requires call tree analysis, to see which auto variables that can be overlapped to use the same global variable. An uncalled function disrupts this call tree analysis and may increase the data need by starting a new call tree for that single function, i.e. the parameters and local variables in that function will not be overlayed with other variables anylonger.
I really stuck on these problem. I am shrinking the code more and more, therefore it is not much code left which I am not calling. Although the data size increase continues. Next problem for me is, that I do not really understand the behaviour of the linker, my understanding based now on your post. I understood your post in this way: If I removed some function call, and these call was the left call on these function, then the linker does not delete these function and hangs with optimization..? The sounds stupid for me, why he does not throw away these function? Or I am on the wrong way?
If I removed some function call, and these call was the left call on these function, then the linker does not delete these function and hangs with optimization..?
A good part of the meaning of that must have been lost in translation.
The linker can't throw away a function just because it can't find a call to it. There's always the chance your program might be calling it via some mechanism (function pointer, RTOS, ...) that the linker has no chance to follow.
And no, the linker doesn't "hang with optimization". It just can't overlay multiple variables in the same RAM space if it doesn't know they will never be in scope at the same time. If the linker can't find how a function is called, it has to assume that it could be active all the time. So its variables have to be in scope continuously, and cannot share memory space with others.
As a result RAM consumption is bigger than if the linker completely understood your program, and eventually there just won't be enough of it. Because no automatic handling of this can work, the linker issues a warning whenever it sees an uncalled function. That leaves the job in the hands of the only instance that can actually handle it: you.
In "nice" programs, you can't call a function without using the name of the function. That would make it simple for the linker to know if a function is used or not.
In an embedded environment, the user may have forced the linker to place the function at an absolute address, and are then using this address instead of the name of the function.
Or the application my perform some form of address calculations, for example by placing another function directly before, and have this function call an unnamed function directly following.
But even if you use a PC compiler, your linker will normally not throw away an unused function. Better linkers will be able to create a map file where unused functions are specifically tagged. Also remember that most linkers can't link smaller units than full object files. If you have a library that contains few but large object files, then you may get most of the library included in an application even if you just use a couple of functions.
Always do your work the correct way - by personally making sure that your code only contains the parts you are interested in.
Thank you for your answers. I think the problem in my code(the code I am working with, I never wrote that crap) is that some functions are in precompiled libraries and if I am linking against them but only using a few of their functions it happens this what you describe... But how can I get out of? If I am only need these few functions, but haven't the source of these libraries? By the way, I did not get warnings for uncalled functions.
Thank you for your help, Chris
What libraries?
Good libraries are normally very granular, to make sure the linker can pick up just the needed functions.
In "nice" programs, you can't call a function without using the name of the function.
It's not quite as simple as that. There's a good deal of ground between calling a function directly by name, and reaching a call to it in some tricky, circuitous way that involves the function's name only several steps away from the actual call.
That would make it simple for the linker to know if a function is used or not.
Not really. In all but the most strictly simple designs there are usually things like callbacks, function pointer tables, or others that the linker can't generally follow. There would be only one conclusion safe for Lx51 to make, in such a situation: that all functions whose address is ever taken and stored somewhere will be running currently both to each other, and to the whole "straight" call-tree. So they would each have to get their own call-tree and variable store. Basically, as soon as a single function pointer is used anywhere in the program, Lx51 would have to turn off overlaying forcibly.
Keil C51's approach to this (warn the user, and let him deal with it) is IMHO a good match to the '51 controller's inherent limitations.
that some functions are in precompiled libraries and if I am linking against them but only using a few of their functions it happens this what you describe
If so, that library is constructed incorrectly. It's one of the basic requirements of proper library design to have each independent functional unit in its own translation unit, so it can be left out of the final link if not needed. Basically, a library must have a separate source file for every single data object and function listed in its interface header(s), and another one for each internal functionality used by more than one other.
Note that callbacks, function pointer tables etc are normally referencing the name of the function, making the linker see that there was a reference to the function, even if the linker can't know if the code will actually make use of this reference.
For a linker, it really does not matter if the function name is referenced several steps away. Just seeing any reference to the function is enough for the linker to drag in the function and - if the MAP file supports it - mark the function as used.
That means that for a "nice" program, the linker will always be able to see a reference to the symbol of the function. But as I mentioned, "non-nice" applications may have placed the function at an absolute address, and then created a direct or indirect call to the function based on this hard-coded address. And a "non-nice" program may place two functions after each other in the same source file, and make a jump/call n bytes past the end of the first function.
A PC program should/must always be nice and never access function without referencing a symbol that makes the linker know what to add to the binary.
An embedded system is quite often not nice. You seldom have a need to make jumps relative the location of another function, but interrupt vector tables, flash sectors etc may be big reasons for placing functions at absolute addresses. And as soon as a function is placed at an absolute address, it will be impossible for the linker to know if other parts of the application, a boot ROM or some hard-coded interrupt logic may perform direct jumps to these addresses.
That is the reason why an embedded linker has to assume that there are unknown code paths reaching the function even if the linker can't see any reference to the function. The linker just can't know if the chip is programmed with a separately linked boot monitor, or if the specific chip has an unusual vectored interrupt system. The calls to absolute addresses may seem "non-nice" but are no different from the normal BIOS calls in a PC.