Obszary Pamięci w C/C++

2023-04-01

W językach C/C++ pamięć jest podzielona na kilka obszarów, które mają różne cele i właściwości. Oto najważniejsze obszary pamięci w C/C++:

 

Wysokie adresy ---> .----------------------.
                    |      Environment     |
                    |----------------------|
                    |                      |   Funkcje i zmienne deklarowane są
                    |         STOS         |   na stosie.
base pointer ->     | - - - - - - - - - - -|
                    |           |          |
                    |           v          |
                    :                      :
                    .                      .   Stos "rośnie w dół" 
                    .      Dostępna        .   Sterta "rośnie w górę" 
                    .      pamięć          .
                    .                      .   
                    .                      .    
                    :                      :    
                    |           ^          |
                    |           |          |
 brk point ->       | - - - - - - - - - - -|   Pamięć dynamiczna
                    |        STERTA        |
                    |                      |
                    |----------------------|
                    |          BSS         |   Dane niezainicjowane (BSS)
                    |----------------------|   
                    |          Data        |   Dane zainicjowane (DS)
                    |----------------------|
                    |          Text        |   Kod binarny
Niskie adresy ----> '----------------------'

 

  1. Stos (Stack): Stos jest obszarem pamięci, który przechowuje zmienne lokalne oraz informacje o wywołaniach funkcji. Stos ma charakterystykę LIFO (Last In, First Out), co oznacza, że elementy są usuwane w kolejności odwrotnej do dodania. W C/C++ stos jest używany głównie do przechowywania zmiennych o krótkim czasie życia, które są związane z czasem życia funkcji, w której są zadeklarowane.
#include <stdio.h>
int main(void)
{
    int data; //zmienne lokalne przechowywane są na stosie
    return 0;
}

 

  1. Sterta (Heap): Sterta to obszar pamięci, który jest używany do dynamicznego przydzielania pamięci. Sterta pozwala na przechowywanie zmiennych o długim czasie życia, które nie są związane z czasem życia funkcji. W C/C++ pamięć na stercie jest przydzielana i zwalniana za pomocą odpowiednich funkcji, takich jak malloc, calloc, realloc i free (w C) lub operatorów new i delete (w C++).
#include <stdio.h>

int main(void)
{
    char *pStr = malloc(sizeof(char)*4); //przechowywane na stercie, warto pamiętać aby nie podawać wartości liczbowych bezpośrednio do sizeof()
    return 0;
}

 

  1. Pamięć kodu (Code memory): Obszar ten przechowuje kod maszynowy programu. Pamięć kodu jest tylko do odczytu, co oznacza, że programista nie może modyfikować zawartości tego obszaru w trakcie działania programu.

 

  1. Pamięć danych (Data memory): Obszar pamięci danych jest podzielony na dwa podobszary: pamięć danych zainicjowanych oraz pamięć danych niezainicjowanych.
#include <stdio.h>

int main(void)
{
    return 0;
}

 

remnux@remnux:~/Documents/code$ type wgcc
    wgcc is aliased to 'x86_64-w64-mingw32-gcc'

remnux@remnux:~/Documents/code$ wgcc main.c -o main.exe  
remnux@remnux:~/Documents/code$ size main.exe

    text    data    bss     dec         hex     filename
    10728   2184    2432    15344       3bf0    main.exe

 

    - Pamięć danych zainicjowanych (Initialized data): Ten obszar przechowuje zmienne globalne i statyczne, które są zainicjowane wartościami niezerowymi. Zmienne te są zadeklarowane na poziomie pliku lub w funkcji jako statyczne, a ich wartości są przypisane podczas kompilacji.

#include <stdio.h>

int zmienna1 = 10; // Zainicjowana zmienna globalna przechowywana w BSS

int main(void)
{
    static int zmienna2 = 20;  // Zainicjowana zmienna statyczna przechowywana w BSS
    return 0;
}
remnux@remnux:~/Documents/code$ wgcc main.c -o z_main.exe  
remnux@remnux:~/Documents/code$ size z_main.exe

    text    data    bss     dec         hex     filename
    10728   2200    2432    15360       3c00    z_win.exe

 

    - Pamięć danych niezainicjowanych (Uninitialized data, BSS - Block Started by Symbol): Ten obszar przechowuje zmienne globalne i statyczne, które są zainicjowane wartościami zerowymi lub nie są zainicjowane w ogóle. BSS jest zazwyczaj wyzerowany przez system operacyjny przed uruchomieniem programu.

#include <stdio.h>

int zmienna1; // Niezainicjowana zmienna globalna przechowywana w BSS

int main(void)
{
    static int zmienna2;  // Niezainicjowana zmienna statyczna przechowywana w BSS
    return 0;
}
remnux@remnux:~/Documents/code$ wgcc main.c -o z_main.exe 
remnux@remnux:~/Documents/code$ size nz_main.exe

    text    data    bss     dec       hex       filename
    10728   2184    2464    15376     3c10      nz_win.exe

 

  1. Pamięć stałych (Constant memory): Ten obszar pamięci przechowuje stałe, takie jak literały łańcuchowe czy wartości liczbowe, które są używane w kodzie programu. Pamięć stałych jest tylko do odczytu, co oznacza, że jej zawartość nie może być modyfikowana w trakcie działania programu. W języku C++ można również korzystać z kwalifikatora const, aby zadeklarować stałe zmienne, które nie mogą być modyfikowane po zainicjowaniu.

#include <stdio.h>

char *str = "Te pieniądze im się po prostu należały";

int main(void)
{
    printf("%s\n",str);
    return 0;
}
remnux@remnux:~/Documents/code$ wgcc main.c -o const_main.exe 
remnux@remnux:~/Documents/code$ size const_main.exe

   text    data     bss     dec     hex filename
  10776    2228    2432   15436    3c4c const_main.exe

 

Podsumowanie

W językach C/C++ pamięć jest podzielona na różne obszary, które mają różne cele i właściwości. Główne obszary pamięci to stos, sterta, pamięć kodu, pamięć danych (zainicjowanej i niezainicjowanej), rejestry procesora oraz pamięć stałych. Zrozumienie tych obszarów pamięci oraz ich zastosowań jest kluczowe dla efektywnego i bezpiecznego zarządzania pamięcią w aplikacjach C/C++.



Więcej podobnych postów

Analiza statyczna - Wprowadzenie

2023-03-18 | #Analiza Statyczna #Podstawy

Statyczna analiza złośliwego oprogramowania to proces badania próbki złośliwego oprogramowania bez jej uruchamiania. W tym wpisie przedstawimy wprowadzenie do statycznej analizy złośliwego oprogramowania, omówimy jej zalety i ograniczenia, a także poznamy niektóre techniki i narzędzia powszechnie stosowane przez badaczy i analityków bezpieczeństwa. Dlaczego statyczna analiza złośliwego oprogramowania? Analiza statyczna może zapewnić cenny wgląd w strukturę, funkcjonalność i intencje próbki złośliwego oprogramowania. Pozwala ona analitykom: Zidentyfikować rodzinę lub wariant złośliwego oprogramowania Odkrycie wbudowanych ciągów znaków i zasobów Odkryć potencjalne wskaźniki kompromisu (IoC) Opracować sygnatury do wykrywania i zapobiegania.

Kontynuuj czytanie 


Dezasemblacja i dekompilacja w analizie złośliwego oprogramowania

2023-03-17 | #dekompilacja #Dezasemblacja #Podstawy

Analiza złośliwego oprogramowania jest krytycznym aspektem zrozumienia i obrony przed cyberzagrożeniami. Jedną z najpotężniejszych technik badania wewnętrznego działania złośliwego oprogramowania jest dezasemblacja i dekompilacja. W tym artykule omówimy znaczenie tych procesów, różnice między nimi oraz narzędzia i techniki wykorzystywane w analizie złośliwego oprogramowania. Znaczenie demontażu i dekompilacji Dezasemblacja i dekompilacja są podstawowymi technikami inżynierii wstecznej złośliwego oprogramowania, aby zrozumieć jego zachowanie, logikę i przepływ kontroli. Badając montaż lub kod źródłowy, analitycy mogą: Zidentyfikować możliwości złośliwego oprogramowania i wektory ataku Odkryć potencjalne luki lub słabości w implementacji złośliwego oprogramowania Opracować środki zaradcze lub sygnatury do wykrywania i zapobiegania atakom Uzyskać wgląd w techniki i taktyki stosowane przez autorów złośliwego oprogramowania.

Kontynuuj czytanie 