This pair of tutorials concentrates on one of the preprocessor directives, namely the #pragma directive. This directive provides the developer with very fine control of the code produced by the C/C++ compiler and it is this fine control we shall be concentrating on here.
The first tutorial looked at the power of the pack directive (found here). This second tutorial concerns itself with how the developer has fine control over where data and functions reside in the executable.
The compiler allocates program declarations to different sections or segments of the object file (and ultimately by the linker into the executable) depending on their usage. For example a constant declaration will be placed into a segment within the executable that when loaded by the operating system will appear in a page that has read-only access. Data declarations will be placed into a segment that when loaded will appear in a page that has read and write access. Functions declarations will appear in a page that has read and execute access.
There are several pragma directives that permit the developer to alter this (although a word of warning might not go amiss here, as it can be potentially very dangerous to start putting constant declarations into memory that will be loaded with read and write access as this could give rise to security issues).
The simple format for this directive is #pragma segment_name("name") where segment_name can be one of bss_seg for uninitialized data, data_seg for initialized data, const_seg for constants and code_seg for function declarations.
Now ordinarily, the developer is not bothered with where exactly data is placed, so long as it is in the correct segment with the correct access rights. Having said that, there are situations where it might be advantageous to specify new segments of a specific type. For example if we were to code the following:
#pragma data_seg("martyn") int this_array;
then providing the segment "martyn" had not been used before, we can guarantee that this_array starts on a page boundary (i.e. the last 12 bits are zero as a page is 4096 bytes in length).
Furthermore, if we changed this slightly and coded:
#pragma data_seg(push) #pragma data_seg("martyn") int this_array; #pragma data_seg(pop) char * foo; #pragma data_seg(push) #pragma data_seg("martyn") int that_array; #pragma data_seg(pop)
then providing the packing was set to one byte, that_array will follow on from this_array seamlessly, even though we have defined foo between the two arrays. This is because foo would be placed in the current segment and not in the segment named "martyn".
I have used this feature in past projects to great effect, but in their infinite wisdom, Microsoft seem to have removed the feature that was present in earlier (years ago) compilers. What you are left with is a set of directives that do not seem to be useful any more! Perhaps you can think of some useful way to use them.
It should be noted that there is also the __pragma keyword which allows you to define segments within a macro.
This post has been edited by Martyn.Rae: 14 April 2011 - 12:04 PM