将内存中的变量与内存中 2 的幂的偏移量对齐
Align a variable in memory with offset from power of two in memory
我想放置一个 2kB 的内存块,16 字节对齐,然后 1024 字节对齐。
平台:arm、裸机、GNU 工具链。不需要便携性
我可以使用 GCC/attributes 编译指示、ld
自定义链接描述文件或任何其他解决方案吗?
我想避免为此浪费 1kB(基本上放置一个 3kB 的内存块以 1kB 对齐并添加 1024-16 字节的填充)。
强制特定地址放置数据是可能的,但 ld
是否能够在其前后放置变量(或者它只是放置填充的一种方式?)
上下文:根据硬件设计,缓冲区需要位于 1k 边界,但我想在之前/之后添加一点空间,以便能够复制到此缓冲区而无需检查我的源是否最多16B 宽。
编辑:添加示例。
假设我的 RAM 从 0x2000000 开始。我需要在其中放置一个 char buf[2048]
,偏移量为 1024*N-16 - 即 (&buf[16])%1024==0
,希望不会丢失 1008 个填充字节。
(edit2)
所以我想要 :
- 0x2000000 - 一些变量
- 0x2000010 - 其他一些变量...
- 0x2000100 - 其他一些变量...
- 0x20003F0 - char buf[2048] : 这里 (int)&buf[16]%1024=0x2000400%1024==0
- 0x2000BF0 - 其他一些变量 ...
您应该在链接描述文件中定义一个特定的部分,并具有所需的对齐方式。
正在查看the man
ALIGN(exp)
Return the result of the current location counter (.) aligned to the next exp boundary. exp must be an expression whose value is a power of two. This is equivalent to
(. + exp - 1) & ~(exp - 1)
ALIGN
doesn't change the value of the location counter--it just does arithmetic on it. As an example, to align the output .data section to the next 0x2000 byte boundary after the preceding section and to set a variable within the section to the next 0x8000 boundary after the input sections:
SECTIONS{ ...
.data ALIGN(0x2000): {
*(.data)
variable = ALIGN(0x8000);
}
... }
The first use of ALIGN in this example specifies the location of a section because it is used as the optional start attribute of a section definition (see section Optional Section Attributes). The second use simply defines the value of a variable. The built-in NEXT is closely related to ALIGN.
例如,您可以定义您的部分
SECTIONS
{
.myBufBlock ALIGN(16) :
{
KEEP(*(.myBufSection))
} > m_data
}
并在您的代码中可以
unsigned char __attribute__((section (".myBufSection"))) buf[2048];
编辑
SECTIONS
{
.myBufBlock 0x0x7FBF0 :
{
KEEP(*(.myBufSection))
} > m_data
}
并在您的代码中可以
unsigned char __attribute__((section (".myBufSection"))) buf[16+2048+16];
对于您的 DMA,您可以设置 1k 对齐的地址 &buf[16]
。
ALIGN(exp)
等价于 (. + exp - 1) & ~(exp - 1)
。当然,该表达式仅在 exp
是 2 的幂时有效。所以你不能使用 ALIGN()
,但你可以编写自己的表达式来产生你想要的结果。 ((. + 1024 + 16 - 1) & ~(1024 - 1)) - 16
之类的东西应该可以解决问题。为 .
插入各种值,您会看到它按您想要的方式四舍五入。
您将遇到的问题是,链接器会将您指定的每个部分放在您的特殊部分之前,并将指定在它之后的每个部分放在它之后。它不会巧妙地将不同文件的 .data 部分排列在之前或之后,以产生最少的填充量。它也根本不会对目标文件和部分中的各个变量进行重新排序。如果你想尽可能紧凑地打包,我认为你需要做类似的事情:
.data : {
*(.about1008bytes)
. = ((. + 1024 + 16 - 1) & ~(1024 - 1)) - 16
*(.DMAbuf)
*(.data)
}
使用节属性将缓冲区放在 .DMAbuf
中,并尝试找到接近但不超过 1008 字节的其他数据变量并将它们粘贴在节 .about1008bytes
.[=20= 中]
如果你想发疯,使用 gcc -fdata-sections
将每个数据对象放在它自己的部分中,使用 readelf 提取部分大小,将其提供给你编写的程序以对它们进行排序以获得最佳包装,然后吐出一大块链接器脚本,以最佳顺序列出它们。
我想放置一个 2kB 的内存块,16 字节对齐,然后 1024 字节对齐。
平台:arm、裸机、GNU 工具链。不需要便携性
我可以使用 GCC/attributes 编译指示、ld
自定义链接描述文件或任何其他解决方案吗?
我想避免为此浪费 1kB(基本上放置一个 3kB 的内存块以 1kB 对齐并添加 1024-16 字节的填充)。
强制特定地址放置数据是可能的,但 ld
是否能够在其前后放置变量(或者它只是放置填充的一种方式?)
上下文:根据硬件设计,缓冲区需要位于 1k 边界,但我想在之前/之后添加一点空间,以便能够复制到此缓冲区而无需检查我的源是否最多16B 宽。
编辑:添加示例。
假设我的 RAM 从 0x2000000 开始。我需要在其中放置一个 char buf[2048]
,偏移量为 1024*N-16 - 即 (&buf[16])%1024==0
,希望不会丢失 1008 个填充字节。
(edit2) 所以我想要 :
- 0x2000000 - 一些变量
- 0x2000010 - 其他一些变量...
- 0x2000100 - 其他一些变量...
- 0x20003F0 - char buf[2048] : 这里 (int)&buf[16]%1024=0x2000400%1024==0
- 0x2000BF0 - 其他一些变量 ...
您应该在链接描述文件中定义一个特定的部分,并具有所需的对齐方式。
正在查看the man
ALIGN(exp)
Return the result of the current location counter (.) aligned to the next exp boundary. exp must be an expression whose value is a power of two. This is equivalent to
(. + exp - 1) & ~(exp - 1)
ALIGN
doesn't change the value of the location counter--it just does arithmetic on it. As an example, to align the output .data section to the next 0x2000 byte boundary after the preceding section and to set a variable within the section to the next 0x8000 boundary after the input sections:
SECTIONS{ ...
.data ALIGN(0x2000): {
*(.data)
variable = ALIGN(0x8000);
}
... }
The first use of ALIGN in this example specifies the location of a section because it is used as the optional start attribute of a section definition (see section Optional Section Attributes). The second use simply defines the value of a variable. The built-in NEXT is closely related to ALIGN.
例如,您可以定义您的部分
SECTIONS
{
.myBufBlock ALIGN(16) :
{
KEEP(*(.myBufSection))
} > m_data
}
并在您的代码中可以
unsigned char __attribute__((section (".myBufSection"))) buf[2048];
编辑
SECTIONS
{
.myBufBlock 0x0x7FBF0 :
{
KEEP(*(.myBufSection))
} > m_data
}
并在您的代码中可以
unsigned char __attribute__((section (".myBufSection"))) buf[16+2048+16];
对于您的 DMA,您可以设置 1k 对齐的地址 &buf[16]
。
ALIGN(exp)
等价于 (. + exp - 1) & ~(exp - 1)
。当然,该表达式仅在 exp
是 2 的幂时有效。所以你不能使用 ALIGN()
,但你可以编写自己的表达式来产生你想要的结果。 ((. + 1024 + 16 - 1) & ~(1024 - 1)) - 16
之类的东西应该可以解决问题。为 .
插入各种值,您会看到它按您想要的方式四舍五入。
您将遇到的问题是,链接器会将您指定的每个部分放在您的特殊部分之前,并将指定在它之后的每个部分放在它之后。它不会巧妙地将不同文件的 .data 部分排列在之前或之后,以产生最少的填充量。它也根本不会对目标文件和部分中的各个变量进行重新排序。如果你想尽可能紧凑地打包,我认为你需要做类似的事情:
.data : {
*(.about1008bytes)
. = ((. + 1024 + 16 - 1) & ~(1024 - 1)) - 16
*(.DMAbuf)
*(.data)
}
使用节属性将缓冲区放在 .DMAbuf
中,并尝试找到接近但不超过 1008 字节的其他数据变量并将它们粘贴在节 .about1008bytes
.[=20= 中]
如果你想发疯,使用 gcc -fdata-sections
将每个数据对象放在它自己的部分中,使用 readelf 提取部分大小,将其提供给你编写的程序以对它们进行排序以获得最佳包装,然后吐出一大块链接器脚本,以最佳顺序列出它们。