当前位置:网站首页>Practice makes sense -- your byte alignment and stack cognition may be wrong
Practice makes sense -- your byte alignment and stack cognition may be wrong
2022-06-13 07:54:00 【Longchizi】
Catalog
zero Introduction
Recently, I was checking a problem , You need to look at the stack of the program . But when analyzing the stack , Something unexpected happened . This breaks my understanding of byte alignment and stack . As the title indicates , True knowledge comes from practice , Sometimes our stereotype may be wrong , And may therefore bring additional unnecessary trouble to the solution of the problem . What is the specific situation , Listen to long chizi. Take your time .
One Inherent cognition
For those with development experience C/C++ As far as Manon is concerned , Knowledge of byte alignment and stack is an essential skill for getting started . During the interview , This kind of problem also occurs frequently . So they are very basic , Very important knowledge .
Again , For coders with development experience , It is very likely that the byte alignment and stack problems are small case, I have already deeply understood , I have mastered it thoroughly . Come on , Let's see. , Is your understanding of these two knowledge points like this :
1 Byte alignment
Byte alignment is related to the structure .CPU During deposit access , In order to improve efficiency , Generally according to 4 Byte alignment (32 position CPU) In a way that . therefore , For structures defined in the code , When saving in memory , Not stored as they are defined . for instance , For the following structure definition :
struct test_align {
char a;
int b;
char c;
int d;
};If char Occupy 1 Bytes ,int Occupy 4 Bytes , stay 32 position CPU In the system , It does not occupy memory as it is actually defined 1 + 4 + 1 + 4 = 10 byte . Do you think it needs 4 + 4 + 4 + 4 = 16 byte . Let's actually verify , After all, the theme of this time is to practice to know .
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
struct test_align {
char a;
int b;
char c;
int d;
};
int main (int argc, char** argv) {
struct test_align testAlign;
printf ("Size of test align struct is %ld\n", sizeof(testAlign));
return 0;
}
g++ Compile and execute

You can see , Expected results , Output 16.
Byte alignment is often used in network programming or device related programming . Sometimes, in order to facilitate the analysis of device data , We might use it pack Force the structure to be byte aligned , That is, compact mode . So there will be no alignment bytes inserted in the middle .
well , So far, , Everything is still under control . Let's look at the stack .
2 Stack
Strictly speaking , What we are going to discuss here is stack . In many materials , You can see the introduction of this aspect , And they are all put together . If you are a learning player , For the stack , Is that your understanding :
Stack is a first in and last out structure ( Queues are first in, first out ), Local variables in programs 、 Function parameters are stored on the stack , Dynamically allocated memory ( Such as malloc) Is saved in the heap . The memory in the stack will be released automatically , Those in the heap need to be released manually . Most people may know that this is the end . Go a little further , You may know not to define too large local variables , Otherwise, it may cause stack overflow error . To properly free memory in the heap , Otherwise, it may cause memory leakage . Go a little further , Stack has full increase and full decrease , The problem of empty increase and empty decrease , Heap memory is the library through brk System calls are applied from the kernel ,brk Allocate... On a page by page basis , The library manages the acquired pages on this basis , Assign... To the application in bytes . Stack down ( From high address to low address ), The heap generally grows upwards ( From low address to high address ).
For the stack , Learn the last point , It's already good .
Okay , In the above basic knowledge or common sense , Let's see what the difference is in practice .
Two The truth
Let's look at it separately . Let's start with byte alignment .
1 Byte alignment
For the following structure definitions , How does it occupy memory (32 position CPU)
struct test_align {
int field32;
long long field64;
};I believe many people will answer yes 4 + 8 = 12. The blogger himself started thinking like this , Think it's 12. that , Is that right? , Let's actually try ( Because now computers are basically 64 Bit environment , So I'm in a arm32 Test in bit environment ):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
struct test_align {
char a;
int b;
char c;
int d;
};
struct test_align1 {
int field32;
long long field64;
};
int main (int argc, char** argv) {
struct test_align testAlign;
printf ("Size of test align struct is %ld\n", sizeof(testAlign));
struct test_align1 testAlign1;
testAlign1.field32 = 1;
testAlign1.field64 = 2;
printf("Size of test align1 struct is %ld \n", sizeof(testAlign1));
return 0;
}
You can see , Actually returned 16, According to 8 Byte aligned . Why use this example , Because bloggers are debugging epoll I had a problem , This structure is similar to epoll in event The structure definition is similar .
struct uv__epoll_event {
uint32_t events;
uint64_t data;
};
In use gdb When getting the contents on the stack address , At first, it didn't correspond to the actual situation ,

It turns out that the alignment conflicts with the inherent thinking . according to 8 Byte alignment , So every two lines above are exactly one structure memory occupation . The first line is the event set , The second line is the descriptor .
Through this example , We can see , The alignment problem is not that simple . Passed in code pack You can force alignment , The compiler can also configure the alignment , The number of platform bytes may also affect alignment .

We force the compiler to follow 4 Byte alignment , Then the output is 12.
In the actual , If alignment may affect the logical correctness of the code , It is recommended to test on the actual compilation environment and platform . Or explicitly specify the alignment . However, the method of mandatory assignment may affect other structures , It is best to limit the scope , Only on related structures , If you follow the compiler configuration above , Then the structure that does not need to be forced may also be forced to affect the overall performance .
2 Stack
For the stack , The basic content has already been introduced . Here we will mainly supplement the contents related to the growth direction . Because this is also closely related to our debugging .
When used gdb When viewing the stack , You might think , How our local variables grow on the stack . Of course ,gdb You can print local variables directly , however , It is useful to know the direction of growth .
A lot of people might think that , The stack grows downward , So the variable defined first is at the high address , The variable defined after is at the low address . There are many such examples on the Internet . that , What is the real situation , Let's practice it :
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
struct test_align {
char a;
int b;
char c;
int d;
};
struct test_align1 {
int field32;
long long field64;
};
struct uv__epoll_event {
uint32_t events;
uint64_t data;
};
int main (int argc, char** argv) {
struct uv__epoll_event events[1024];
struct uv__epoll_event e;
struct test_align testAlign;
printf ("Size of test align struct is %ld\n", sizeof(testAlign));
struct test_align1 testAlign1;
testAlign1.field32 = 1;
testAlign1.field64 = 2;
printf("Size of test align1 struct is %ld \n", sizeof(testAlign1));
printf("Local events addr is %p \n", events);
printf("Local e addr is %p \n", &e);
return 0;
}In the code main The beginning of the function , We define two local variables . Then compile on the local machine first , function .

You can see , First defined at high address 0x7fff500f4080, After defined in the low address 0x7fff500f4060, This is in line with our expectations for downward stack growth .
Let's go to the front arm Try it under the platform environment .

You can see , here , The local variables defined first are assigned 0xbed60c70 Address , The local variable defined later is assigned an address 0xbed64c90, The stack is growing up .
If we add compile options to the compiler -fstack-protector, What will happen ?

At this point, the situation has changed , The stack starts to grow down , It meets the initial expectation .
This is an example , The direction of stack growth is also related to compiler configuration . For the current test arm platform , In the kernel layer , The stack grows downward .
in addition , For the first array of local variables , What are the array items inside ? Is the high subscript at the low address ? Interested readers can verify . This is still in line with expectations , Just follow the normal train of thought , Increase from low address to high address .
3、 ... and summary
From the above two examples, we can see , Byte alignment and stack details , It is very relevant to the compilation environment , If you need gdb Debug your own program , And you need to look at the stack , If the feeling doesn't match the expectation , So it is very necessary to verify the above two points . also , If debugging involves the kernel , For example, system call , Maybe the stack growth of the kernel is different from that of the application . Last , In fact, there are many contents that are not covered here , Interested readers can further explore . doubt -- verification -- doubt -- verification , It is a good practical learning method .
边栏推荐
- IDS persistence ---rdb
- 20 | 面向流水线的指令设计(上):一心多用的现代CPU
- 2022年电工(初级)考题及模拟考试
- IIS中的网站访问excel
- China phosphate market in-depth analysis and investment prospect forecast report 2022-2028
- [deep learning]: introduction to pytorch to project practice (XII) convolutional neural network: padding and stride
- 22 | adventure and prediction (I): hazard is both "danger" and "opportunity"
- 18 | establish data path (middle): instruction + operation =cpu
- Considerations for using redis transactions
- Data disorder occurs when the n-th row of the subcomponent list generated by V-for is deleted
猜你喜欢

v-for生成的子组件列表删除第n行出现数据错乱问题

EHD ether coin, the hottest dpoc mining project

分布式系统之道:Lamport 逻辑时钟

23 | adventure and prediction (II): relay race in the assembly line

2022年电工(初级)考题及模拟考试

20 | 面向流水线的指令设计(上):一心多用的现代CPU

Consistency under distributed

Openharmony notes ----------- (I)

Tidb certification guide PCTA Pctp

25 | adventure and prediction (IV): it's raining today. Will it rain tomorrow?
随机推荐
Redis underlying data structure ----quicklist
24 | adventure and prediction (III): thread pool in CPU
Compare advantages and disadvantages of DFS and BFS and name vocabulary
MySQL table partitioning
Data disorder occurs when the n-th row of the subcomponent list generated by V-for is deleted
QT reading SQLSERVER database
[log4j2 log framework] modify dump log file permissions
Redis interview questions
udf_ interval_ to_ Hourno() function
基于paddlepaddle的新冠肺炎识别
18 | 建立数据通路(中):指令+运算=CPU
【深度学习】:《PyTorch入门到项目实战》(十二)卷积神经网络:填充(padding)和步幅(stride)
8. process status and transition
Examination question bank and simulation examination for special operation certificate of safety management personnel of hazardous chemical business units in 2022
免费文件服务器储存技术
Selenium reports an error deprecationwarning: executable_ path has been deprecated, please pass in a Service object
Go 接口实现原理【高阶篇】: type _interface struct
Considerations for using redis transactions
Idea shortcut summary
Redis learning journey -- getting to know redis for the first time