当前位置:网站首页>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 .
边栏推荐
- 18 | establish data path (middle): instruction + operation =cpu
- 本地靶场2-文件上传漏洞(三)-网络安全
- [problem record] taberror: inconsistent use of tabs and spaces in indentation
- 20 | pipeline oriented instruction design (Part 1): Modern CPU with multi-purpose
- Leetcode 163 Missing interval (June 12, 2022)
- EHD ether coin, the hottest dpoc mining project
- 23 | 冒险和预测(二):流水线里的接力赛
- P7712 [Ynoi2077] hlcpq
- JMeter common commands
- [MySQL] rapid data deletion recovery tool - binlog2sql
猜你喜欢
Redis learning journey -- getting to know redis for the first time
实践出真知--你的字节对齐和堆栈认知可能是错误的
[problem record] json decoder. JSONDecodeError:Extra data: line xxx column xxx(char xxxx)
[MySQL change master error] slave is not configured or failed to initialize properly
11.29 Li Kou swipes questions every day
2021-10-08
Install cuda+cusp environment and create the first helloword starter project
Find the first and last positions of elements in a sorted array
Redis learning journey master-slave replication
Redis' underlying data structure -- SDS
随机推荐
MySQL table partitioning
平衡二叉树学习笔记------一二熊猫
LATERAL VIEW explode
Simple use of logs
Upgrade the project of log4j to log4j2
MySQL source code --table_ cache
22 | adventure and prediction (I): hazard is both "danger" and "opportunity"
MySQL summary
【PYTORCH】RuntimeError: torch. cuda. FloatTensor is not enabled.
Pdf to word
leetcode 咒语和药水的成功对数
【PYTORCH】RuntimeError: one of the variables needed for gradient computation has been
Selenium reports an error deprecationwarning: executable_ path has been deprecated, please pass in a Service object
MySQL row column conversion (updated version)
Effective Go - The Go Programming Language
mysql面试题
17 | establish data path (upper): instruction + operation =cpu
Redis learning journey -- subscription and publishing
[pytorch] pytorch0.4.0 installation tutorial and GPU configuration collection (including test code)
uniapp 小程序根据权限动态生成 tabbar