Minimum çalıştırılabilir örnek
Brk () sistem çağrısı ne yapar?
Çekirdekten, yığın adı verilen bitişik bir bellek yığınını okumanıza ve yazmanıza izin vermesini ister.
Eğer sormazsanız, sizi parçalayabilir.
Olmadan brk
:
#define _GNU_SOURCE
#include <unistd.h>
int main(void) {
/* Get the first address beyond the end of the heap. */
void *b = sbrk(0);
int *p = (int *)b;
/* May segfault because it is outside of the heap. */
*p = 1;
return 0;
}
İle brk
:
#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>
int main(void) {
void *b = sbrk(0);
int *p = (int *)b;
/* Move it 2 ints forward */
brk(p + 2);
/* Use the ints. */
*p = 1;
*(p + 1) = 2;
assert(*p == 1);
assert(*(p + 1) == 2);
/* Deallocate back. */
brk(b);
return 0;
}
GitHub akış yukarı .
Yukarıdakiler, yeni bir sayfaya brk
çarpmayabilir ve olmadan bile segfault yapamaz , bu nedenle 16MiB'yi ayıran ve agresif olmayan brk
:
#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>
int main(void) {
void *b;
char *p, *end;
b = sbrk(0);
p = (char *)b;
end = p + 0x1000000;
brk(end);
while (p < end) {
*(p++) = 1;
}
brk(b);
return 0;
}
Ubuntu 18.04'te test edildi.
Sanal adres alanı görselleştirme
Önce brk
:
+------+ <-- Heap Start == Heap End
Sonra brk(p + 2)
:
+------+ <-- Heap Start + 2 * sizof(int) == Heap End
| |
| You can now write your ints
| in this memory area.
| |
+------+ <-- Heap Start
Sonra brk(b)
:
+------+ <-- Heap Start == Heap End
Adres alanlarını daha iyi anlamak için, disk belleği hakkında bilgi sahibi olmalısınız: x86 disk belleği nasıl çalışır? .
Neden ikisine de ihtiyacımız var brk
ve sbrk
?
brk
Elbette sbrk
+ ofset hesaplamaları ile uygulanabilir , her ikisi de sadece kolaylık sağlamak için mevcuttur.
Arka uçta, Linux çekirdeği v5.0, brk
her ikisini de uygulamak için kullanılan tek bir sistem çağrısına sahiptir: https://github.com/torvalds/linux/blob/v5.0/arch/x86/entry/syscalls/syscall_64. tbl # L23
12 common brk __x64_sys_brk
Mı brk
POSIX?
brk
eskiden POSIX idi, ancak POSIX 2001'de kaldırıldı, bu nedenle _GNU_SOURCE
glibc sarmalayıcısına erişme ihtiyacı .
Kaldırma işlemi büyük olasılıkla mmap
, birden fazla aralığın atanmasına izin veren bir üst küme ve daha fazla ayırma seçeneğinden kaynaklanmaktadır.
Bugün brk
yerine malloc
ya da yerine kullanmanız gereken geçerli bir durum olmadığını düşünüyorum mmap
.
brk
vs malloc
brk
eski bir uygulama olasılığıdır malloc
.
mmap
şu anda tüm POSIX sistemlerinin uygulamak için kullandığı daha yeni ve daha güçlü bir mekanizmadır malloc
. İşte asgari çalıştırılabilir mmap
bellek ayırma örneği .
Karıştırıp brk
yanlış yerleştirebilir miyim ?
Eğer malloc
uygulandıysa brk
, bunun nasıl bir şeyleri havaya uçuramayacağı hakkında hiçbir fikrim yok, çünkü brk
sadece tek bir bellek aralığını yönetiyor.
Ancak glibc belgelerinde bu konuda bir şey bulamadım, örneğin:
Muhtemelen orada mmap
kullanıldığından beri işler muhtemelen orada çalışacaktır malloc
.
Ayrıca bakınız:
Daha fazla bilgi
Dahili olarak, işlemin bu kadar fazla belleğe sahip olup olamayacağına karar verir ve bu kullanım için bellek sayfalarını belirler .
Bu, yığının yığınla nasıl karşılaştırıldığını açıklar: x86 derlemesindeki kayıtlarda kullanılan push / pop yönergelerinin işlevi nedir?