当前位置:网站首页>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

One Inherent cognition

1 Byte alignment

2 Stack

Two The truth

1 Byte alignment

2 Stack

3、 ... and summary


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 .

原网站

版权声明
本文为[Longchizi]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/164/202206130751473498.html