diff mbox

[U-Boot,2/3,V2] common: Implement support for linker-generated arrays

Message ID 1348589520-14395-3-git-send-email-marex@denx.de
State Changes Requested
Delegated to: Wolfgang Denk
Headers show

Commit Message

Marek Vasut Sept. 25, 2012, 4:11 p.m. UTC
This patch adds support for linker-generated array. These arrays
are a generalization of the U-Boot command declaration approach.

Basically, the idea is to generate an array, where elements of the
array are statically initialized at compiler time and each element
is declared separatelly at different place. Such array though can
later be accessed and used via special accessor.

The actual implementation relies on placing any variable that is to
represent an element of LG-array into subsection of .u_boot_list
linker section . Once compiled, it is possible to dump all symbols
placed in .u_boot_list section and generate appropriate bounds for
each subsection of the .u_boot_list section. Each such subsection
this contains .__start and .__end entries at the begining and end
respecitively.

This allows for simple run-time traversing of the array, since the
symbols are properly defined.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Joe Hershberger <joe.hershberger@gmail.com>
Cc: Mike Frysinger <vapier@gentoo.org>
---
 include/linker_lists.h |  124 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)
 create mode 100644 include/linker_lists.h

V2: Don't define the variable twice in ll_entry_declare()

Comments

Wolfgang Denk Sept. 25, 2012, 8:16 p.m. UTC | #1
Dear Marek Vasut,

In message <1348589520-14395-3-git-send-email-marex@denx.de> you wrote:
> This patch adds support for linker-generated array. These arrays
> are a generalization of the U-Boot command declaration approach.
...

>                                         ... Such array though can
> later be accessed and used via special accessor.

Can you please translate this to me?  I don't get what it means.


> The actual implementation relies on placing any variable that is to
> represent an element of LG-array into subsection of .u_boot_list

"into subsection" ? Do you mean "into a subsection", or "into a
specific subsection" or what?

...
> --- /dev/null
> +++ b/include/linker_lists.h
...
> +/**
> + * ll_entry_declare() - Declare linker-generated array entry
...

Incorrect multiline comment style. Please fix globally.

Best regards,

Wolfgang Denk
Marek Vasut Sept. 25, 2012, 8:24 p.m. UTC | #2
Dear Wolfgang Denk,

> Dear Marek Vasut,
> 
> In message <1348589520-14395-3-git-send-email-marex@denx.de> you wrote:
> > This patch adds support for linker-generated array. These arrays
> > are a generalization of the U-Boot command declaration approach.
> 
> ...
> 
> >                                         ... Such array though can
> > 
> > later be accessed and used via special accessor.
> 
> Can you please translate this to me?  I don't get what it means.

That you call a function that returns the pointer to the first member of the 
array.

> 
> > The actual implementation relies on placing any variable that is to
> > represent an element of LG-array into subsection of .u_boot_list
> 
> "into subsection" ? Do you mean "into a subsection", or "into a
> specific subsection" or what?


... into a matching subsection ...

> ...
> 
> > --- /dev/null
> > +++ b/include/linker_lists.h
> 
> ...
> 
> > +/**
> > + * ll_entry_declare() - Declare linker-generated array entry
> 
> ...
> 
> Incorrect multiline comment style. Please fix globally.

You mean what ...

/**
 *

This? Kernel-doc style ...

> Best regards,
> 
> Wolfgang Denk

Best regards,
Marek Vasut
Wolfgang Denk Sept. 26, 2012, 7:01 a.m. UTC | #3
Dear Marek,

In message <201209252224.32686.marex@denx.de> you wrote:
> 
> > >                                         ... Such array though can
> > > later be accessed and used via special accessor.
> > 
> > Can you please translate this to me?  I don't get what it means.
> 
> That you call a function that returns the pointer to the first member of the 
> array.

then please write this down?

Do we always need such a function?  Where is it coming from?
Auto-generated?  What about the memory footprint?

> You mean what ...
> 
> /**
>  *
> 
> This? Kernel-doc style ...

It violates the kernel CodyngStyle...

Best regards,

Wolfgang Denk
Marek Vasut Sept. 26, 2012, 4:53 p.m. UTC | #4
Dear Wolfgang Denk,

> Dear Marek,
> 
> In message <201209252224.32686.marex@denx.de> you wrote:
> > > >                                         ... Such array though can
> > > > 
> > > > later be accessed and used via special accessor.
> > > 
> > > Can you please translate this to me?  I don't get what it means.
> > 
> > That you call a function that returns the pointer to the first member of
> > the array.
> 
> then please write this down?

I rewrote it, it made no sense.

> Do we always need such a function?  Where is it coming from?

It's not a function, macro, sorry for the confusion

> Auto-generated?  What about the memory footprint?

None, it's a macro. Doing exactly what &__u_boot_cmd... did, but instead of 
doing it at n places, it does so at one place now and is expanded as needed.

> > You mean what ...
> > 
> > /**
> > 
> >  *
> > 
> > This? Kernel-doc style ...
> 
> It violates the kernel CodyngStyle...

Yes, well ... let's discuss it.

> Best regards,
> 
> Wolfgang Denk

Best regards,
Marek Vasut
Joe Hershberger Sept. 29, 2012, 1:45 a.m. UTC | #5
Hi Marek,

On Tue, Sep 25, 2012 at 11:11 AM, Marek Vasut <marex@denx.de> wrote:
> This patch adds support for linker-generated array. These arrays
> are a generalization of the U-Boot command declaration approach.
>
> Basically, the idea is to generate an array, where elements of the
> array are statically initialized at compiler time and each element
> is declared separatelly at different place. Such array though can
> later be accessed and used via special accessor.
>
> The actual implementation relies on placing any variable that is to
> represent an element of LG-array into subsection of .u_boot_list
> linker section . Once compiled, it is possible to dump all symbols
> placed in .u_boot_list section and generate appropriate bounds for
> each subsection of the .u_boot_list section. Each such subsection
> this contains .__start and .__end entries at the begining and end
> respecitively.
>
> This allows for simple run-time traversing of the array, since the
> symbols are properly defined.
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Joe Hershberger <joe.hershberger@gmail.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> ---
>  include/linker_lists.h |  124 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 124 insertions(+)
>  create mode 100644 include/linker_lists.h
>
> V2: Don't define the variable twice in ll_entry_declare()
>
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> new file mode 100644
> index 0000000..27ae40b
> --- /dev/null
> +++ b/include/linker_lists.h

[...]

> +/**
> + * ll_entry_count() - Return the number of elements in linker-generated array
> + * _type:      Data type of the entry
> + * _section_u: Subsection of u_boot_list in which this entry is placed
> + *             (with underscores instead of dots)
> + *
> + * This function returns the number of elements of a linker-generated array
> + * placed into subsection of .u_boot_list section specified by _section_u
> + * argument. The result is of an unsigned int type.
> + *
> + * Example of usage:
> + *
> + * int i;
> + * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub);
> + * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub);
> + * for (i = 0; i < count; i++) {
> + *     printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y);
> + *     msc++;
> + * }
> + */
> +#define ll_entry_count(_type, _section_u)                              \
> +       ({                                                              \
> +               extern _type _u_boot_list_##_section_u##__start;        \
> +               extern _type _u_boot_list_##_section_u##__end;          \
> +               unsigned int _ll_result =                               \
> +                       &_u_boot_list_##_section_u##__end -             \
> +                       &_u_boot_list_##_section_u##__start;            \
> +               _ll_result;                                             \
> +       })

While ll_entry_count is great and all, it is more natural to compare
your list pointer to The End (tm) or not.  It would make client code
capable of being cleaner if you also include ll_entry_end() as well.

Thanks,
-Joe
Marek Vasut Sept. 29, 2012, 2:49 a.m. UTC | #6
Dear Joe Hershberger,

[...]


> While ll_entry_count is great and all, it is more natural to compare
> your list pointer to The End (tm) or not.  It would make client code
> capable of being cleaner if you also include ll_entry_end() as well.

Ain't that

#define ll_entry_end(_type, u) \
ll_entry_start(_type, u) + ll_entry_count(_type, u)

...

_type *end = ll_entry_end(_type, u);

?

> Thanks,
> -Joe

Best regards,
Marek Vasut
diff mbox

Patch

diff --git a/include/linker_lists.h b/include/linker_lists.h
new file mode 100644
index 0000000..27ae40b
--- /dev/null
+++ b/include/linker_lists.h
@@ -0,0 +1,124 @@ 
+/*
+ * include/linker_lists.h
+ *
+ * Implementation of linker-generated arrays
+ *
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+#ifndef __LINKER_LISTS_H__
+#define __LINKER_LISTS_H__
+
+/**
+ * ll_entry_declare() - Declare linker-generated array entry
+ * _type:	Data type of the entry
+ * _name:	Name of the entry
+ * _section_u:	Subsection of u_boot_list in which this entry is placed
+ *		(with underscores instead of dots, for name concatenation)
+ * _section_d:	Subsection of u_boot_list in which this entry is placed
+ *		(with dots, for section concatenation)
+ *
+ * This macro declares a variable that is placed into a linker-generated
+ * array. This is a basic building block for more advanced use of linker-
+ * generated arrays. The user is expected to build their own macro wrapper
+ * around this one.
+ *
+ * A variable declared using this macro must be compile-time initialized
+ * and is as such placed into subsection of special section, .u_boot_list.
+ * The subsection is specified by the _section_[u,d] parameter, see below.
+ * The base name of the variable is _name, yet the actual variable is
+ * declared as concatenation of:
+ *
+ *   _u_boot_list_ + _section_u + _ + _name
+ *
+ * which ensures name uniqueness. This variable shall never be refered
+ * directly though.
+ *
+ * Special precaution must be made when using this macro:
+ *
+ * 1) The _type must not contain the "static" keyword, otherwise the entry
+ *    is not generated.
+ * 2) The _section_u and _section_d variables must match, the only difference
+ *    is that in _section_u is every dot "." character present in _section_d
+ *    replaced by a single underscore "_" character in _section_u. The actual
+ *    purpose of these parameters is to select proper subsection in the global
+ *    .u_boot_list section.
+ * 3) In case a section is declared that contains some array elements AND a
+ *    subsection of this section is declared and contains some elements, it is
+ *    imperative that the elements are of the same type.
+ * 4) In case an outer section is declared that contains some array elements
+ *    AND am inner subsection of this section is declared and contains some
+ *    elements, then when traversing the outer section, even the elements of
+ *    the inner sections are present in the array.
+ *
+ * Example of usage:
+ *
+ * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = {
+ *	.x = 3,
+ *	.y = 4,
+ * };
+ */
+#define ll_entry_declare(_type, _name, _section_u, _section_d)		\
+	_type _u_boot_list_##_section_u##_##_name __attribute__((	\
+			unused,	aligned(4),				\
+			section(".u_boot_list."#_section_d"."#_name)))
+
+/**
+ * ll_entry_start() - Point to first entry of linker-generated array
+ * _type:	Data type of the entry
+ * _section_u:	Subsection of u_boot_list in which this entry is placed
+ *		(with underscores instead of dots)
+ *
+ * This function returns (_type *) pointer to the very first entry of a
+ * linker-generated array placed into subsection of .u_boot_list section
+ * specified by _section_u argument.
+ *
+ * Example of usage:
+ *
+ * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub);
+ */
+#define ll_entry_start(_type, _section_u)				\
+	({								\
+		extern _type _u_boot_list_##_section_u##__start;	\
+		_type *_ll_result = &_u_boot_list_##_section_u##__start;\
+		_ll_result;						\
+	})
+
+/**
+ * ll_entry_count() - Return the number of elements in linker-generated array
+ * _type:	Data type of the entry
+ * _section_u:	Subsection of u_boot_list in which this entry is placed
+ *		(with underscores instead of dots)
+ *
+ * This function returns the number of elements of a linker-generated array
+ * placed into subsection of .u_boot_list section specified by _section_u
+ * argument. The result is of an unsigned int type.
+ *
+ * Example of usage:
+ *
+ * int i;
+ * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub);
+ * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub);
+ * for (i = 0; i < count; i++) {
+ *	printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y);
+ *	msc++;
+ * }
+ */
+#define ll_entry_count(_type, _section_u)				\
+	({								\
+		extern _type _u_boot_list_##_section_u##__start;	\
+		extern _type _u_boot_list_##_section_u##__end;		\
+		unsigned int _ll_result =				\
+			&_u_boot_list_##_section_u##__end -		\
+			&_u_boot_list_##_section_u##__start;		\
+		_ll_result;						\
+	})
+
+#endif	/* __LINKER_LISTS_H__ */