Hi all,
With gas, does anyone know of a way to create a section whose name is based on that of the current section?
The specific requirement is to be able to define a generic macro like the example "fixup" below, whose purpose is to record ancilliary data related to some other section. To illustrate:
.macro fixup 100@ : .pushsection fixup<current section name>, "a" .long 100@b .popsection .endm
.text ... fixup .long sym1 ...
.section .other, "ax" ... fixup .long sym2
The linux kernel uses a technique just like this for patching SMP kernels at bootup to work on uniprocessor platforms (when CONFIG_SMP_ON_UP is enabled), resulting in code looking something like this:
void exit __attribute__ (( __section__ (".text.exit") )) { ... asm( ... FIXUP("something") ... ); }
Note that the inline asm may actually come out of a generic header file rather than being explitly written for this invocation. So it may have to be truly generic.
Is far as I have been able to determine, it's not possible to generate sections named based on the current section. In practice, the kernel puts all the fixups into a single section.
The downside of this is that when sections are selectively discarded at link time (which in general may happen -- for example, Linux discards the "module exit" code for drivers which are built into the kernel and therefore never exit) there is no way to selectively discard the related fixup entries. Currently the only solution is to include all the module exit code in the image and discard it at run-time when the kernel boots. This is obviously wasteful. Attempting to discard that code at like time results in a link error, since fixups refer to the removed sections.
Of course, the "fixup" macro could be given an extra parameter to name the containing section, but the macro can then no longer be called in a generic way: all the calls to that macro must be manually (and buggily) maintained to ensure that the referenced section name is correct, some object post-processing must be done before linking, and/or a tool must be created to implement the missing assembler functionality. Unfortunately, such solutions are likely to be too fragile or complex to make it upstream.
It's interesting to note that the same problem will apply for any section containing ancilliary data for another section. In particular, it looks like either the ABI or the assembler has had to grow a special-case workaround for this in order to support exception unwind information sections generated by .fnstart ... .fnend in a sane way: the unwind information sections get called .ARM.ex{idx,tab} for .text, and .ARM.ex{idx,tab}<section> for any other section. As a consequence, link-time discarding can handle this information properly, but IMHO this is a bit of a cheat and admits the general need to create sections with names based transparently on those of other sections, without satisfying that need. .popsection is also an example of such a cheat: most other aspects of assmbler state still cannot be saved and restored.
In general, it would be useful if gas supported some general reflective abilities: i.e., the ability to query the current assembler state (section, subsection, active instruction set, active macro mode, etc.) and/or the ability to wrap or hook existing pseudo-ops. For example, the above problem would almost certainly solvable using assembler macros (albeit painfully) if wrapper macros could be defined for the section manipulation directives (section, .text, .data, .bss, .pushsection, .popsection, .previous). However, supporting some magic macro parameters reflecting the assembler state would be a lot simpler.
As an example of the kind of behaviour I think would be useful, the macro argument qualifier could be extended to allow macros to query the assembler state in a backwards-compatible way; something like:
.macro fixup base_section:gas_current_section_name, old_altmacro:gas_macro_mode .altmacro LOCAL fixup_location
fixup_location: .pushsection \base_section().fixup .long 100@b .popsection
\old_altmacro .endm
Existing assembler code will continue to work just fine with this approach.
Note how this also enables a local label to be generated hygenically, by making it possible to save and restore the macro mode. Otherwise, .altmacro (and hence LOCAL) is hard to use safely, since the initial macro mode is unknown and can't be restored.
Any thoughts / comments?
Cheers. ---Dave
Hi all,
Every now and again I come across a situation where it would be really useful to be able to query the assembler state during assembly: for example, to query and do something based on the current section name. This makes it possible to write generic macros to do certain things which otherwise require manual maintenance, or complex and fragile external preprocessing.
Below, I give a real-world example of the problem, and sketch out a possible solution.
What do people think of this approach? Does anyone have any better ideas on how to solve this?
Cheers ---Dave
EXAMPLE
An example is the generation of custom ancilliary sections. Suppose you want to write macros which record fixup information. Currently, there's no way to put each fixup in an appropriately named section automatically within gas. Tellingly, gas has had to grow the ability to do this internally at least for ARM, since the exception handling information in .ARM.ex{idx,tab}* must go in sections with names based on the associated section name. However, this ancillary section generation support is neither flexible nor exposed to the user.
By putting fixups in sections whose names are based on the name of the section they refer to, selective link-time discard of the fixups (and hence the code referenced by the fixups) will work; otherwise it doesn't. This would help avoid a situation where we have to keep dead code in the kernel because custom fixups are applied to it: at run-time, the code gets fixed up, then is thrown away. The fixups can't be selectively discarded because they are all in the same section: we seem have to no good way to separate them out into separate sections appropriately.
For context, see: http://www.spinics.net/lists/arm-kernel/msg112268.html
PROPOSAL
To solve the problem of generating custom ancillary sections during assembly, here's a simple proposal: introducing a new kind of macro argument can make aspects of the assembler state available to macros in a flexible way, with only minimal implementation required.
Basically, the macro qualifier field could be used to identify arguments which are filled in by the assembler with information about the assembly state, rather than being filled in by the invoker of the macro: e.g.:
.macro mymacro name:req, flags, secname:current_section /* ... */ .pushsection "\secname\name", "\flags" /* ... */ .popsection .endm
/* ... */
mymacro .ancillary, "a"
During expansion, \name and \flags are expanded as normal. But \secname is substituted instead with the current section name, so the macro expansion would look like this:
/* ... */ .pushsection ".text.ancillary", "a" /* ... */ .popsection
Without the special :current_section argument, it doesn't appear possible to implement a macro such as mymacro in a generic way.
This surely isn't the only way to achieve the goal, and it's probably not the best way, but it does have some desirable features.
Principally, while a new pseudo-op(s) could have been defined to append text to the current section name, etc., allowing the current section name to be appear as a macro parameter avoids prejudicing the way the text is used. So there should never be a need to introduce additional pseudo-ops to do things with the current section name: with this patch, the user can always implement their own macro to do the desired thing. This gets the desired behaviour and maximum flexibility, while keeping the implementation in gas very simple.
Also, using the macro expansion system in this way allows the caller a free choice of macro parameter names, and so pretty much guarantees that existing code won't get broken by the change.
Because my hack is currently simplistic, it has shortcomings: in particular, it's not desirable to parse an argument from the invocation line at all to fill a :current_section argument. Currently, an argument is read in if present, but its value is ignored and the current section name pasted in at macro expansion time instead. However, that should be straightforward to fix with a bit more code.
Of course, there's no reason only to expose the current section name in this way. Any aspect of the the assembler state (current subsection, current section flags, current instruction set, current macro mode, etc.) could be made available in a similar way.
USAGE EXAMPLE AND PATCH
Note that the specific implementation described here is intended to be illustrative, rather than complete or final.
binutils$ cat <<EOF >tst.s .macro push_ancillary_section name:req, flags, csec:current_section .pushsection "\name\csec", "\flags" .endm
.macro register_fixup _register_fixup 100@ .endm
.macro _register_fixup label:req \label : push_ancillary_section .fixup, "a" .long \label(b) .popsection .endm
.long 1 register_fixup .long 2
.data .long 3 register_fixup .long 4 .long 5 register_fixup .long 6 EOF
binutils$ gas/as-new -ahlms -o tst.o tst.s ARM GAS tst.s page 1
1 .macro push_ancillary_section name:req, flags, csec:current_section 2 .pushsection "\name\csec", "\flags" 3 .endm 4 5 .macro register_fixup 6 _register_fixup 100@ 7 .endm 8 9 .macro _register_fixup label:req 10 \label : 11 push_ancillary_section .fixup, "a" 12 .long \label(b) 13 .popsection 14 .endm 15 16 0000 01000000 .long 1 17 register_fixup 17 > _register_fixup 1000 17 >> 1000: 17 >> push_ancillary_section .fixup,"a" 17 >>> .pushsection ".fixup.text","a" 17 0000 04000000 >> .long 1000b 17 >> .popsection 18 0004 02000000 .long 2 19 20 .data 21 0000 03000000 .long 3 22 register_fixup 22 > _register_fixup 1003 22 >> 1003: 22 >> push_ancillary_section .fixup,"a" 22 >>> .pushsection ".fixup.data","a" 22 0000 04000000 >> .long 1003b 22 >> .popsection 23 0004 04000000 .long 4 24 0008 05000000 .long 5 25 register_fixup 25 > _register_fixup 1006 25 >> 1006: 25 >> push_ancillary_section .fixup,"a" 25 >>> .pushsection ".fixup.data","a" 25 0004 0C000000 >> .long 1006b 25 >> .popsection 26 000c 06000000 .long 6 ARM GAS tst.s page 2
NO DEFINED SYMBOLS
NO UNDEFINED SYMBOLS
binutils$ arm-linux-gnueabi-objdump -rs tst.o
tst.o: file format elf32-littlearm
RELOCATION RECORDS FOR [.fixup.text]: OFFSET TYPE VALUE 00000000 R_ARM_ABS32 .text
RELOCATION RECORDS FOR [.fixup.data]: OFFSET TYPE VALUE 00000000 R_ARM_ABS32 .data 00000004 R_ARM_ABS32 .data
Contents of section .text: 0000 01000000 02000000 ........ Contents of section .data: 0000 03000000 04000000 05000000 06000000 ................ Contents of section .fixup.text: 0000 04000000 .... Contents of section .fixup.data: 0000 04000000 0c000000 ........ Contents of section .ARM.attributes: 0000 41150000 00616561 62690001 0b000000 A....aeabi...... 0010 08010901 2c01 ....,.
diff --git a/gas/macro.c b/gas/macro.c index e392883..95c4de1 100644 --- a/gas/macro.c +++ b/gas/macro.c @@ -516,6 +516,8 @@ do_formals (macro_entry *macro, int idx, sb *in) formal->type = FORMAL_REQUIRED; else if (strcmp (qual.ptr, "vararg") == 0) formal->type = FORMAL_VARARG; + else if (strcmp (qual.ptr, "current_section") == 0) + formal->type = FORMAL_CURRENT_SECTION; else as_bad_where (macro->file, macro->line, @@ -540,6 +542,15 @@ do_formals (macro_entry *macro, int idx, sb *in) name, macro->name); } + else if (formal->type == FORMAL_CURRENT_SECTION) + { + sb_reset (&formal->def); + as_warn_where (macro->file, + macro->line, + _("Pointless default value for current_section parameter `%s' in macro `%s'"), + name, + macro->name); + } }
/* Add to macro's hash table. */ @@ -734,7 +745,11 @@ sub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash, ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); if (ptr) { - if (ptr->actual.len) + if (ptr->type == FORMAL_CURRENT_SECTION) + { + sb_add_string (out, segment_name (now_seg)); + } + else if (ptr->actual.len) { sb_add_sb (out, &ptr->actual); } diff --git a/gas/macro.h b/gas/macro.h index edc1b6b..ea6cabb 100644 --- a/gas/macro.h +++ b/gas/macro.h @@ -38,7 +38,8 @@ enum formal_type { FORMAL_OPTIONAL, FORMAL_REQUIRED, - FORMAL_VARARG + FORMAL_VARARG, + FORMAL_CURRENT_SECTION, };
/* Describe the formal arguments to a macro. */
Have you seen http://sourceware.org/ml/binutils/2010-08/msg00121.html ?
On Tue, Feb 1, 2011 at 11:48 PM, Alan Modra amodra@gmail.com wrote:
Have you seen http://sourceware.org/ml/binutils/2010-08/msg00121.html ?
That's interesting--- I hadn't fully understood what this did.
I'm not sure it solves my problem though: I need to generate ancillary sectiions relating for normal sections, and I need the relationship to be visible in the name so that a linker script can remove related sections in a sane way.
I think my proposal allows for a solution to the general problem of allowing assembler directives to do things based on the current assembler state, where "?" solves only a specific instance of that problem, just allowing .section and related directives to do something quite specific based on a specific property of the assembler state (the current section group name).
If I'm wrong and you can see how to solve my problem, I'd definitely be interested though.
Cheers ---Dave
linaro-toolchain@lists.linaro.org