Skip to contentSkip to conversation

Translate asm version of ELFNOTE macro into preprocessor macro

PATCH In review Ian Campbell 3 participants 8 messages Aug 23, 2006 virtio core

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Translate asm version of ELFNOTE macro into preprocessor macro

Hi,

I've come across some problems with the assembly version of the ELFNOTE macro currently in -mm. (in x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch)

The first is that older gas does not support :varargs in .macro definitions (in my testing 2.17 does while 2.15 does not, I don't know when it became supported). The Changes file says binutils >= 2.12 so I think we need to avoid using it. There are no other uses in mainline or -mm. Old gas appears to just ignore it so you get "too many arguments" type errors.

Secondly it seems that passing strings as arguments to assembler macros is broken without varargs. It looks like they get unquoted or each character is treated as a separate argument or something and this causes all manner of grief. I think this is because of the use of -traditional when compiling assembly files.

Therefore I have translated the assembler macro into a pre-processor macro.

I added the desctype as a separate argument instead of including it with the descdata as the previous version did since -traditional means the ELFNOTE definition after the #else needs to have the same number of arguments (I think so anyway, the -traditional CPP semantics are pretty fscking strange!).

With this patch I am able to define elfnotes in assembly like this with both old and new assemblers.

	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz, "linux")	
	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz, "2.6")
	ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz, "xen-3.0")
	ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE,      .long,  __PAGE_OFFSET)

Which seems reasonable enough.

include/linux/elfnote.h +17 -15
diff -r 4b7cd997c08f include/linux/elfnote.h
@@ -31,22 +31,24 @@
 /*
  * Generate a structure with the same shape as Elf{32,64}_Nhdr (which
  * turn out to be the same size and shape), followed by the name and
- * desc data with appropriate padding.  The 'desc' argument includes
- * the assembler pseudo op defining the type of the data: .asciz
- * "hello, world"
+ * desc data with appropriate padding.  The 'desctype' argument is the
+ * assembler pseudo op defining the type of the data e.g. .asciz while
+ * 'descdata' is the data itself e.g.  "hello, world".
+ *
+ * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
+ *      ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
  */
-.macro ELFNOTE name type desc:vararg
-.pushsection ".note.\name"
-  .align 4
-  .long 2f - 1f			/* namesz */
-  .long 4f - 3f			/* descsz */
-  .long \type
-1:.asciz "\name"
-2:.align 4
-3:\desc
-4:.align 4
-.popsection
-.endm
+#define ELFNOTE(name, type, desctype, descdata)	\
+.pushsection .note.name			;	\
+  .align 4				;	\
+  .long 2f - 1f		/* namesz */	;	\
+  .long 4f - 3f		/* descsz */	;	\
+  .long type				;	\
+1:.asciz "name"				;	\
+2:.align 4				;	\
+3:desctype descdata			;	\
+4:.align 4				;	\
+.popsection				;
 #else	/* !__ASSEMBLER__ */
 #include <linux/elf.h>
 /*
#1 lore raw
Quoted 7 lines · Ian Campbell

The first is that older gas does not support :varargs in .macro definitions (in my testing 2.17 does while 2.15 does not, I don't know when it became supported). The Changes file says binutils >= 2.12 so I think we need to avoid using it. There are no other uses in mainline or -mm. Old gas appears to just ignore it so you get "too many arguments" type errors.

OK, seems reasonable. Eric Biederman solved this by having NOTE/ENDNOTE (or something like that) in his "bzImage with ELF header" patch, but I don't remember it being used in any way which is incompatible with using a CPP macro.

J

#2 lore raw
Quoted 8 lines · Jeremy Fitzhardinge
Quoted 7 lines · Ian Campbell

The first is that older gas does not support :varargs in .macro definitions (in my testing 2.17 does while 2.15 does not, I don't know when it became supported). The Changes file says binutils >= 2.12 so I think we need to avoid using it. There are no other uses in mainline or -mm. Old gas appears to just ignore it so you get "too many arguments" type errors.

Quoted 4 lines

OK, seems reasonable. Eric Biederman solved this by having NOTE/ENDNOTE (or something like that) in his "bzImage with ELF header" patch, but I don't remember it being used in any way which is incompatible with using a CPP macro.

I can't find that patch, does NOTE/ENDNOTE just do the push/pop .note section?

That would solve the problem with the first argument of the macro being a string but the final argument could still be for .asciz note contents.

Ian.

#3 lore raw
Quoted 9 lines · Ian Campbell
Quoted 2 lines

OK, seems reasonable. Eric Biederman solved this by having NOTE/ENDNOTE (or something like that) in his "bzImage with ELF header" patch, but I don't remember it being used in any way which is incompatible with using a CPP macro.

I can't find that patch, does NOTE/ENDNOTE just do the push/pop .note section?

That would solve the problem with the first argument of the macro being a string but the final argument could still be for .asciz note contents.

It looks like:

.macro note name, type
.balign 4
.int 2f - 1f # n_namesz
.int 4f - 3f # n_descsz
.int \type # n_type
.balign 4
1: .asciz "\name"
2: .balign 4
3:
.endm
.macro enote
4: .balign 4
.endm

so it allows you to put arbitrary stuff in the desc part of the note. The downside is that its a little more cumbersome syntactically for the common case.

J

#4 lore raw
Quoted 31 lines · Jeremy Fitzhardinge
Quoted 6 lines · Ian Campbell
Quoted 5 lines

OK, seems reasonable. Eric Biederman solved this by having NOTE/ENDNOTE (or something like that) in his "bzImage with ELF header" patch, but I don't remember it being used in any way which is incompatible with using a CPP macro.

Quoted 6 lines

I can't find that patch, does NOTE/ENDNOTE just do the push/pop .note section?

That would solve the problem with the first argument of the macro being a string but the final argument could still be for .asciz note contents.

It looks like:

.macro note name, type
.balign 4
.int 2f - 1f # n_namesz
.int 4f - 3f # n_descsz
.int \type # n_type
.balign 4
1: .asciz "\name"
2: .balign 4
3:
.endm
.macro enote
4: .balign 4
.endm

Quoted 2 lines

so it allows you to put arbitrary stuff in the desc part of the note. The downside is that its a little more cumbersome syntactically for the common case.

I don't expect it to be much more cumbersome, as two pieces, and you need the extra alignment at the end to ensure each not entry is 4 byte aligned. Being able to push and pop a section wouldn't hurt either.

Eric

#5 lore raw
Quoted 11 lines · Eric W. Biederman
Quoted 8 lines · Jeremy Fitzhardinge
Quoted 6 lines · Ian Campbell
Quoted 6 lines

OK, seems reasonable. Eric Biederman solved this by having NOTE/ENDNOTE (or something like that) in his "bzImage with ELF header" patch, but I don't remember it being used in any way which is incompatible with using a CPP macro.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

I can't find that patch, does NOTE/ENDNOTE just do the push/pop .note section?

That would solve the problem with the first argument of the macro being a string but the final argument could still be for .asciz note contents.

I remember now why I decided to use the assembler macro rather than cpp. The macro names the section after the note name (".note.NAME"), and it needs to be quoted so that the name can have spaces and other characters which would otherwise upset the assembler. I couldn't work out a clean way to do this with the C preprocessor, since "as" doesn't support string concatenation like C does.

Quoted 2 lines

I don't expect it to be much more cumbersome, as two pieces, and you need the extra alignment at the end to ensure each not entry is 4 byte aligned.

Isn't it enough that each entry start have the alignment? But you need some kind of end marker to get the size of the desc field regardless.

Quoted 2 lines

Being able to
push and pop a section wouldn't hurt either.

Yes, I think having each note contain its own .pushsection/popsection is the cleaner way of doing it.

J

#6 lore raw
Quoted 7 lines · Jeremy Fitzhardinge

I remember now why I decided to use the assembler macro rather than cpp. The macro names the section after the note name (".note.NAME"), and it needs to be quoted so that the name can have spaces and other characters which would otherwise upset the assembler. I couldn't work out a clean way to do this with the C preprocessor, since "as" doesn't support string concatenation like C does.

Surprisingly string concatenation doesn't appear to be required for the majority of punctuation, at least so far as I can tell with this test patch (this is a xen-unstable kernel I had lying around so don't pay too much attention to head-xen.S bit). The only problem I found is comma, which can't be escaped.

I've no idea how reliably this works across tool chain versions etc though. It worked for me ;-)

include/linux/elfnote.h +1 -1
@@ -39,7 +39,7 @@
  *      ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
  */
 #define ELFNOTE(name, type, desctype, descdata)	\
-.pushsection .note.name			;	\
+.pushsection ".note.name"		;	\
   .align 4				;	\
   .long 2f - 1f		/* namesz */	;	\
   .long 4f - 3f		/* descsz */	;	\
linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S +8 -0
diff -r 58b5141c8309 linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S
@@ -199,3 +199,11 @@ ENTRY(cpu_gdt_table)
 	ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz, "no")
 #endif
 	ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz, "generic")
+
+	ELFNOTE(XYZ Co., 42, .asciz, "forty-two")
+	ELFNOTE(XYZ Co., 12, .long, 0xdeadbeef)
+	ELFNOTE(!\"£$%^\\&, 12, .long, 0xdeadbeef)
+	ELFNOTE(*\(\)-+-=<, 12, .long, 0xdeadbeef)
+	ELFNOTE(>./?\;\'#:, 12, .long, 0xdeadbeef)
+	ELFNOTE(@~, 12, .long, 0xdeadbeef)
+
$ readelf -S --segments arch/i386/kernel/head-xen.o
...
  [ 7] .note.Xen         NOTE            00000000 002260 000144 00      0   0  4
  [ 8] .rel.note.Xen     REL             00000000 003018 000010 08     15   7  4
  [ 9] .note.XYZ Co.     NOTE            00000000 0023a4 000038 00      0   0  4
  [10] .note.!"£$%^\&   NOTE            00000000 0023dc 00001c 00      0   0  4
  [11] .note.*()-+-=<    NOTE            00000000 0023f8 00001c 00      0   0  4
  [12] .note.>./?;'#:    NOTE            00000000 002414 00001c 00      0   0  4
  [13] .note.@~          NOTE            00000000 002430 000014 00      0   0  4
...
$ objdump -j .notes -s vmlinux
...
 85a8 72696300 08000000 0a000000 2a000000  ric.........*...
 85b8 58595a20 436f2e00 666f7274 792d7477  XYZ Co..forty-tw
 85c8 6f000000 08000000 04000000 0c000000  o...............
 85d8 58595a20 436f2e00 efbeadde 0a000000  XYZ Co..........
 85e8 04000000 0c000000 2122c2a3 24255e5c  ........!"..$%^\
 85f8 26000000 efbeadde 09000000 04000000  &...............
 8608 0c000000 2a28292d 2b2d3d3c 00000000  ....*()-+-=<....
 8618 efbeadde 09000000 04000000 0c000000  ................
 8628 3e2e2f3f 3b27233a 00000000 efbeadde  >./?;'#:........
 8638 03000000 04000000 0c000000 407e0000  ............@~..
 8648 efbeadde                             ....
...
#7 lore raw
Quoted 9 lines · Ian Campbell

Surprisingly string concatenation doesn't appear to be required for the majority of punctuation, at least so far as I can tell with this test patch (this is a xen-unstable kernel I had lying around so don't pay too much attention to head-xen.S bit). The only problem I found is comma, which can't be escaped.

I've no idea how reliably this works across tool chain versions etc though. It worked for me ;-)

I guess that's a broad enough selection of names. I had assumed it would impose normal symbol-like restrictions on the unquoted section name. (I guess ';' would also need quoting.)

J