我正在用ARM9处理器编写C for Linux程序.该程序用于访问网络数据包,其中包括一系列标记数据,如:
<fieldID><length><data><fieldID><length><data> ...
Run Code Online (Sandbox Code Playgroud)
fieldID和length字段都是uint16_t.数据可以是1个或更多字节(如果使用全长,则最多64k,但事实并非如此).
只要<data>有一个偶数个字节,我就没有看到问题.但是,如果我有一个1或3或5字节的<data>部分,那么下一个16位fieldID最终不会出现在16位边界上,我预计会出现对齐问题.已经有一段时间了,因为我从头开始做了这样的事情,所以我对细节不太了解.任何反馈欢迎.谢谢.
背景:
我有一个优化的Delphi/BASM例程单元,主要用于繁重的计算.其中一些例程包含内部循环,如果循环开始与DQWORD(16字节)边界对齐,我可以实现显着的加速.如果我知道例程入口点的对齐,我可以确保所讨论的循环按照需要对齐.
据我所知,Delphi编译器将过程/函数与DWORD边界对齐,例如向单元添加函数可能会改变后续函数的对齐.但是,只要我将例程的结尾填充到16的倍数,我就可以确保后续例程同样对齐 - 或未对齐,这取决于第一个例程的对齐方式.因此,我尝试将关键例程放在单元实现部分的开头,并在它们之前放置一些填充代码,以便第一个过程与DQWORD对齐.
这看起来如下所示:
interface
procedure FirstProcInUnit;
implementation
procedure __PadFirstProcTo16;
asm
// variable number of NOP instructions here to get the desired code length
end;
procedure FirstProcInUnit;
asm //should start at DQWORD boundary
//do something
//padding to align the following label to DQWORD boundary
@Some16BAlignedLabel:
//code, looping back to @Some16BAlignedLabel
//do something else
ret #params
//padding to get code length to multiple of 16
end;
initialization
__PadFirstProcTo16; //call this here so that it isn't optimised out
ASSERT ((NativeUInt(Pointer(@FirstProcInUnit)) …Run Code Online (Sandbox Code Playgroud) 的Objective-C运行提供class_addIvar C函数:
BOOL class_addIvar(Class cls, const char *name, size_t size,
uint8_t alignment, const char *types)
Run Code Online (Sandbox Code Playgroud)
我该怎么把为size和alignment?
我正在添加一个类型的实例变量UITextPosition *,但没有UITextPosition对象在范围内.因为size,我可以做sizeof(self),哪个self是子类UITextField?即,我可以假设一个UITextPosition对象与对象的大小相同UITextField吗?
我怎么得到alignment?
我正在玩一下以更好地掌握调用约定以及如何处理堆栈,但我无法弄清楚为什么main在设置堆栈时会分配三个额外的双字(at <main+0>).它既没有与8个字节对齐,也没有16个字节,所以这并不是我所知道的原因.正如我所看到的,main需要12个字节才能将两个参数设置为func和返回值.
我错过了什么?
该程序是在x86架构上使用"gcc -ggdb"编译的C代码.
编辑:我从gcc中删除了-O0标志,它对输出没有任何影响.
(gdb) disas main
Dump of assembler code for function main:
0x080483d1 <+0>: sub esp,0x18
0x080483d4 <+3>: mov DWORD PTR [esp+0x4],0x7
0x080483dc <+11>: mov DWORD PTR [esp],0x3
0x080483e3 <+18>: call 0x80483b4 <func>
0x080483e8 <+23>: mov DWORD PTR [esp+0x14],eax
0x080483ec <+27>: add esp,0x18
0x080483ef <+30>: ret
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
编辑:当然我应该发布C代码:
int func(int a, int b) {
int c = 9;
return a + b + c;
}
void main() {
int x;
x = …Run Code Online (Sandbox Code Playgroud) 快问人......这些代码spinets是否具有相同的对齐方式?
struct sse_t {
float sse_data[4];
};
// the array "cacheline" will be aligned to 64-byte boundary
struct sse_t alignas(64) cacheline[1000000];
Run Code Online (Sandbox Code Playgroud)
要么
// every object of type sse_t will be aligned to 64-byte boundary
struct sse_t {
float sse_data[4];
} __attribute((aligned(64)));
struct sse_t cacheline[1000000];
Run Code Online (Sandbox Code Playgroud) 我刚刚发现ARM我正在编写代码(Cortex M0),不支持未对齐的内存访问.
现在在我的代码中我使用了很多打包结构,而且我从来没有得到任何警告或硬错误,那么当它不允许未对齐访问时,Cortex如何访问这些结构的成员?
我在MS代码示例中看到了下一个代码:
PVOID alignedBuffer[BUFFER_SIZE/sizeof( PVOID )];
PCHAR buffer = (PCHAR) alignedBuffer;
hResult = FilterSendMessage( context->Port,
&commandMessage,
sizeof( COMMAND_MESSAGE ),
buffer,
sizeof(alignedBuffer),
&bytesReturned );
Run Code Online (Sandbox Code Playgroud)
(alignedBuffer将保存作为重放传递给FilterSendMessage调用的结构数组)将PVOID转换为PCHAR的意义是什么,这有助于对齐,如何?
我真的很想了解这两行发生了什么
const int PAGES = 8 * 1024;
// PAGES + extra 4KiB for alignment
uint8_t * mem = new uint8_t [ PAGES * CCPU::PAGE_SIZE + CCPU::PAGE_SIZE ];
// align to a mutiple of 4KiB
uint8_t * memAligned = (uint8_t *) (( ((uintptr_t) mem) + CCPU::PAGE_SIZE - 1) & ~(uintptr_t) ~CCPU::ADDR_MASK );
Run Code Online (Sandbox Code Playgroud)
特别是最后一行,我什么都不懂......
在C++中,似乎所有的整数类型(int,long long int,std::uint16_t,...)和浮点类型,它始终是sizeof(T) == alignof(T).
这个编译器/平台是特定的,还是保证是真的?是否有一个平台,其中int32_ts不需要在32位边界上对齐(只要它们不重叠)?
我理解填充是如何工作的.我知道对齐是什么.对我来说奇怪的是,为什么只有char字段的struct的大小不对齐到4个字节(末尾的填充)?我怀疑这不是规范所保证的,所以编译器不这样做.如果是这种情况,我可以参考这样的规则吗?我最感兴趣的是x86和x86-64架构.
例:
struct foo {
char field1;
char field2;
char field3;
} foo2;
int main(void)
{
printf("sizeof=%lu\n", sizeof foo2);
}
Run Code Online (Sandbox Code Playgroud)
输出: sizeof=3