All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [PATCH v3 01/28] linker_lists: Fix alignment issue
Date: Wed, 16 Dec 2020 21:20:06 -0700	[thread overview]
Message-ID: <20201216212001.v3.1.Ie3fa227cbe539fa6742fa1e647093557a2b9b8ee@changeid> (raw)
In-Reply-To: <20201217042034.411902-1-sjg@chromium.org>

The linker script uses alphabetic sorting to group the different linker
lists together. Each group has its own struct and potentially its own
alignment. But when the linker packs the structs together it cannot ensure
that a linker list starts on the expected alignment boundary.

For example, if the first list has a struct size of 8 and we place 3 of
them in the image, that means that the next struct will start at offset
0x18 from the start of the linker_list section. If the next struct has
a size of 16 then it will start at an 8-byte aligned offset, but not a
16-byte aligned offset.

With sandbox on x86_64, a reference to a linker list item using
ll_entry_get() can force alignment of that particular linker_list item,
if it is in the same file as the linker_list item is declared.

Consider this example, where struct driver is 0x80 bytes:

	ll_entry_declare(struct driver, fred, driver)

...

	void *p = ll_entry_get(struct driver, fred, driver)

If these two lines of code are in the same file, then the entry is forced
to be aligned at the 'struct driver' alignment, which is 16 bytes. If the
second line of code is in a different file, then no action is taken, since
the compiler cannot update the alignment of the linker_list item.

In the first case, an 8-byte 'fill' region is added:

 .u_boot_list_2_driver_2_testbus_drv
                0x0000000000270018       0x80 test/built-in.o
                0x0000000000270018                _u_boot_list_2_driver_2_testbus_drv
 .u_boot_list_2_driver_2_testfdt1_drv
                0x0000000000270098       0x80 test/built-in.o
                0x0000000000270098                _u_boot_list_2_driver_2_testfdt1_drv
 *fill*         0x0000000000270118        0x8
 .u_boot_list_2_driver_2_testfdt_drv
                0x0000000000270120       0x80 test/built-in.o
                0x0000000000270120                _u_boot_list_2_driver_2_testfdt_drv
 .u_boot_list_2_driver_2_testprobe_drv
                0x00000000002701a0       0x80 test/built-in.o
                0x00000000002701a0                _u_boot_list_2_driver_2_testprobe_drv

With this, the linker_list no-longer works since items after testfdt1_drv
are not at the expected address.

Ideally we would have a way to tell gcc not to align structs in this way.
It is not clear how we could do this, and in any case it would require us
to adjust every struct used by the linker_list feature.

One possible fix is to force each separate linker_list to start on the
largest possible boundary that can be required by the compiler. However
that does not seem to work on x86_64, which uses 16-byte alignment in this
case but needs 32-byte alignment.

So add a Kconfig option to handle this. Set the default value to 4 so
as to avoid changing platforms that don't need it.

Update the ll_entry_start() accordingly.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 arch/Kconfig             | 11 ++++++++
 doc/api/linker_lists.rst | 59 ++++++++++++++++++++++++++++++++++++++++
 include/linker_lists.h   |  3 +-
 3 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index e8f9a9e1b77..27843cd79c4 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -7,6 +7,17 @@ config HAVE_ARCH_IOREMAP
 config NEEDS_MANUAL_RELOC
 	bool
 
+config LINKER_LIST_ALIGN
+	int
+	default 32 if SANDBOX
+	default 8 if ARM64 || X86
+	default 4
+	help
+	  Force the each linker list to be aligned to this boundary. This
+	  is required if ll_entry_get() is used, since otherwise the linker
+	  may add padding into the table, thus breaking it.
+	  See linker_lists.rst for full details.
+
 choice
 	prompt "Architecture select"
 	default SANDBOX
diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
index 72f514e0ac0..7063fdc8314 100644
--- a/doc/api/linker_lists.rst
+++ b/doc/api/linker_lists.rst
@@ -96,5 +96,64 @@ defined for the whole list and each sub-list:
   %u_boot_list_2_drivers_2_pci_3
   %u_boot_list_2_drivers_3
 
+Alignment issues
+----------------
+
+The linker script uses alphabetic sorting to group the different linker
+lists together. Each group has its own struct and potentially its own
+alignment. But when the linker packs the structs together it cannot ensure
+that a linker list starts on the expected alignment boundary.
+
+For example, if the first list has a struct size of 8 and we place 3 of
+them in the image, that means that the next struct will start at offset
+0x18 from the start of the linker_list section. If the next struct has
+a size of 16 then it will start at an 8-byte aligned offset, but not a
+16-byte aligned offset.
+
+With sandbox on x86_64, a reference to a linker list item using
+ll_entry_get() can force alignment of that particular linker_list item,
+if it is in the same file as the linker_list item is declared.
+
+Consider this example, where struct driver is 0x80 bytes::
+
+    ll_entry_declare(struct driver, fred, driver)
+
+    ...
+
+    void *p = ll_entry_get(struct driver, fred, driver)
+
+If these two lines of code are in the same file, then the entry is forced
+to be aligned at the 'struct driver' alignment, which is 16 bytes. If the
+second line of code is in a different file, then no action is taken, since
+the compiler cannot update the alignment of the linker_list item.
+
+In the first case, an 8-byte 'fill' region is added::
+
+   .u_boot_list_2_driver_2_testbus_drv
+               0x0000000000270018       0x80 test/built-in.o
+               0x0000000000270018                _u_boot_list_2_driver_2_testbus_drv
+   .u_boot_list_2_driver_2_testfdt1_drv
+               0x0000000000270098       0x80 test/built-in.o
+               0x0000000000270098                _u_boot_list_2_driver_2_testfdt1_drv
+   *fill*         0x0000000000270118        0x8
+   .u_boot_list_2_driver_2_testfdt_drv
+               0x0000000000270120       0x80 test/built-in.o
+               0x0000000000270120                _u_boot_list_2_driver_2_testfdt_drv
+   .u_boot_list_2_driver_2_testprobe_drv
+               0x00000000002701a0       0x80 test/built-in.o
+               0x00000000002701a0                _u_boot_list_2_driver_2_testprobe_drv
+
+With this, the linker_list no-longer works since items after testfdt1_drv
+are not at the expected address.
+
+Ideally we would have a way to tell gcc not to align structs in this way.
+It is not clear how we could do this, and in any case it would require us
+to adjust every struct used by the linker_list feature.
+
+The simplest fix seems to be to force each separate linker_list to start
+on the largest possible boundary that can be required by the compiler. This
+is the purpose of CONFIG_LINKER_LIST_ALIGN
+
+
 .. kernel-doc:: include/linker_lists.h
    :internal:
diff --git a/include/linker_lists.h b/include/linker_lists.h
index d775d041e04..fd98ecd297c 100644
--- a/include/linker_lists.h
+++ b/include/linker_lists.h
@@ -124,7 +124,8 @@
  */
 #define ll_entry_start(_type, _list)					\
 ({									\
-	static char start[0] __aligned(4) __attribute__((unused,	\
+	static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN)	\
+		__attribute__((unused,					\
 		section(".u_boot_list_2_"#_list"_1")));			\
 	(_type *)&start;						\
 })
-- 
2.29.2.684.gfbc64c5ab5-goog

  reply	other threads:[~2020-12-17  4:20 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-17  4:20 [PATCH v3 00/28] dm: Change the way sequence numbers are implemented Simon Glass
2020-12-17  4:20 ` Simon Glass [this message]
2021-04-15  7:39   ` [PATCH v3 01/28] linker_lists: Fix alignment issue Heinrich Schuchardt
2021-04-21  7:14     ` Simon Glass
2020-12-17  4:20 ` [PATCH v3 02/28] dm: Avoid accessing seq directly Simon Glass
2020-12-17  4:20 ` [PATCH v3 03/28] dm: core: Update uclass_find_next_free_req_seq() args Simon Glass
2020-12-17  4:20 ` [PATCH v3 04/28] dm: core: Add a new sequence number for devices Simon Glass
2020-12-17  4:20 ` [PATCH v3 05/28] dm: test: Check all devices have a sequence numbers Simon Glass
2020-12-17  4:20 ` [PATCH v3 06/28] dm: core: Switch binding to use new " Simon Glass
2020-12-17  4:20 ` [PATCH v3 07/28] dm: Fix return value in dev_read_alias_seq() Simon Glass
2020-12-17  4:20 ` [PATCH v3 08/28] dm: test: Drop assumptions of no sequence numbers Simon Glass
2020-12-17  4:20 ` [PATCH v3 09/28] octeon: Don't attempt to set the sequence number Simon Glass
2020-12-17  4:20 ` [PATCH v3 10/28] i2c: Update for new sequence numbers Simon Glass
2020-12-17  4:20 ` [PATCH v3 11/28] net: Update to use " Simon Glass
2020-12-17  4:20 ` [PATCH v3 12/28] dm: core: Allow manual sequence numbering Simon Glass
2020-12-17  4:20 ` [PATCH v3 13/28] pci: Update to use new sequence numbers Simon Glass
2020-12-17  4:20 ` [PATCH v3 14/28] spi: Update for " Simon Glass
2020-12-17  4:20 ` [PATCH v3 15/28] usb: ehci-mx6: Drop assignment of sequence number Simon Glass
2020-12-17  4:20 ` [PATCH v3 16/28] usb: Update for new sequence numbers Simon Glass
2020-12-17  4:20 ` [PATCH v3 17/28] x86: Drop unnecessary mp_init logic Simon Glass
2020-12-17  4:20 ` [PATCH v3 18/28] x86: Simplify acpi_device_infer_name() Simon Glass
2020-12-17  4:20 ` [PATCH v3 19/28] gpio: Update for new sequence numbers Simon Glass
2020-12-17  4:20 ` [PATCH v3 20/28] pinctrl: " Simon Glass
2020-12-17  4:20 ` [PATCH v3 21/28] dm: Switch over to use new sequence number for dev_seq() Simon Glass
2020-12-17  4:20 ` [PATCH v3 22/28] dm: test: Add a test for DM_UC_FLAG_NO_AUTO_SEQ Simon Glass
2020-12-17  4:20 ` [PATCH v3 23/28] dm: Drop uclass_resolve_seq() Simon Glass
2020-12-17  4:20 ` [PATCH v3 24/28] dm: Drop the unused arg in uclass_find_device_by_seq() Simon Glass
2020-12-17  4:20 ` [PATCH v3 25/28] dm: core: Update uclass_find_next_free_req_seq() for new scheme Simon Glass
2020-12-17  4:20 ` [PATCH v3 26/28] cmd: Drop use of old sequence numbers in commands Simon Glass
2020-12-17  4:20 ` [PATCH v3 27/28] dm: core: Drop seq and req_seq Simon Glass
2020-12-17  4:20 ` [PATCH v3 28/28] dm: Update documentation for new sequence numbers Simon Glass
2020-12-18 11:09 ` [PATCH v3 00/28] dm: Change the way sequence numbers are implemented Michael Walle
2020-12-19 16:40 ` [PATCH v3 28/28] dm: Update documentation for new sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 27/28] dm: core: Drop seq and req_seq Simon Glass
2020-12-19 16:40 ` [PATCH v3 25/28] dm: core: Update uclass_find_next_free_req_seq() for new scheme Simon Glass
2020-12-19 16:40 ` [PATCH v3 26/28] cmd: Drop use of old sequence numbers in commands Simon Glass
2020-12-19 16:40 ` [PATCH v3 24/28] dm: Drop the unused arg in uclass_find_device_by_seq() Simon Glass
2020-12-19 16:40 ` [PATCH v3 23/28] dm: Drop uclass_resolve_seq() Simon Glass
2020-12-19 16:40 ` [PATCH v3 22/28] dm: test: Add a test for DM_UC_FLAG_NO_AUTO_SEQ Simon Glass
2020-12-19 16:40 ` [PATCH v3 21/28] dm: Switch over to use new sequence number for dev_seq() Simon Glass
2020-12-19 16:40 ` [PATCH v3 20/28] pinctrl: Update for new sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 19/28] gpio: " Simon Glass
2020-12-19 16:40 ` [PATCH v3 18/28] x86: Simplify acpi_device_infer_name() Simon Glass
2020-12-19 16:40 ` [PATCH v3 17/28] x86: Drop unnecessary mp_init logic Simon Glass
2020-12-19 16:40 ` [PATCH v3 16/28] usb: Update for new sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 15/28] usb: ehci-mx6: Drop assignment of sequence number Simon Glass
2021-03-31 19:14   ` Marek Vasut
2021-03-31 19:27     ` Tom Rini
2021-03-31 22:20       ` Simon Glass
2020-12-19 16:40 ` [PATCH v3 14/28] spi: Update for new sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 13/28] pci: Update to use " Simon Glass
2021-04-13 18:32   ` Tim Harvey
2021-04-14 19:37     ` Simon Glass
2021-04-15  0:28       ` Tim Harvey
2021-04-15  0:44         ` Simon Glass
2020-12-19 16:40 ` [PATCH v3 12/28] dm: core: Allow manual sequence numbering Simon Glass
2020-12-19 16:40 ` [PATCH v3 11/28] net: Update to use new sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 10/28] i2c: Update for " Simon Glass
2020-12-19 16:40 ` [PATCH v3 09/28] octeon: Don't attempt to set the sequence number Simon Glass
2020-12-19 16:40 ` [PATCH v3 08/28] dm: test: Drop assumptions of no sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 07/28] dm: Fix return value in dev_read_alias_seq() Simon Glass
2020-12-19 16:40 ` [PATCH v3 06/28] dm: core: Switch binding to use new sequence numbers Simon Glass
2020-12-19 16:40 ` [PATCH v3 05/28] dm: test: Check all devices have a " Simon Glass
2020-12-19 16:40 ` [PATCH v3 04/28] dm: core: Add a new sequence number for devices Simon Glass
2020-12-19 16:40 ` [PATCH v3 03/28] dm: core: Update uclass_find_next_free_req_seq() args Simon Glass
2020-12-19 16:40 ` [PATCH v3 02/28] dm: Avoid accessing seq directly Simon Glass
2020-12-19 16:40 ` [PATCH v3 01/28] linker_lists: Fix alignment issue Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201216212001.v3.1.Ie3fa227cbe539fa6742fa1e647093557a2b9b8ee@changeid \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.