Kullanıcı uzayında tanımlanan bir değişkenin fiziksel adresini bulmak ister misiniz? Kök ayrıcalıkları kullanarak bunu yapmak için herhangi bir yolu var mı?Linux'ta bir kullanıcı değişkeninin fiziksel adresini nasıl bulabilirim?
cevap
Öncelikle bunu neden istesin? Modern VM sistemlerinin amacı, uygulama programlayıcısını, fiziksel bellek düzeninin karmaşıklığından çıkarmaktır. Hayatlarını daha kolay hale getirmek için her birinin kendi tek adres alanını açarak.
Bunu yapmak istiyorum olmadıysa neredeyse certanly bir çekirdek modülü kullanmak gerekir. Değişkenin sanal adresini normal şekilde alın, bunu işlem sayfaları tablolarına dizinlemek ve bulduğunuz değeri (çerçevenin fiziksel adresi) okumak için kullanın. Daha sonra, tüm fiziksel adresi almak için sayfa ofseti ekleyin. Sayfalama etkinken bu adresi kullanamayacağınızı unutmayın.
(Eğer bir çekirdek modülü yazmak için ihtiyaç olmaz böylece/proc dosya sisteminden bir VM bölgenin çerçeve adresini almak mümkün olabilir ve şanslı.)
... ile ilgili diğer bilgiler ve Sayfayı belleğe kilitlersiniz, fiziksel adres her an değişebilir. – caf
Bir çekirdek modülü yazmanıza gerek yoktur: diğer örnekler açıkladığı gibi, bu zaten '/ proc/$ pid/pagemap' üzerinden gösterilmektedir. – poolie
Değişkenlerin fiziksel adresini bilmek NUMA mimarisinde ilginç olabilir – horro
(düzenleme: tarafından "Eğer fiziksel adres hangi" ise, düzeyini demek 'RAM modülü benim bit depolanmaz', sonra aşağıdaki cevap uygun değildir.)
Bunu yapmak için root yetkileri gerekmez. Bunun yerine ihtiyacınız olan bir hata ayıklayıcıdır. Ve burada (x86_64'lerde Linux sistemini kullanarak) gidin:
Önce oynamak için biraz program gerekiyor. Bu bir global değişkene erişir ve iki kez üst üste basar. Daha sonra bellekte bulduğumuz iki küresel değişkene sahiptir.
#include <stdio.h> int a, b = 0; int main(void) { printf("a: "); if (fscanf("%d", &a) < 1) return 0; printf("a = %d\n", myglobal); printf("b: "); if (fscanf("%d", &b) < 1) return 0; printf("a = %d, b = %d\n", a, b); return 0; }
Adım 1: Programı derlemek ve ondan tüm hata ayıklama bilgilerini şerit, biz de, gerçek hayattaki bir durumda alacağı yok ayıklayıcıya herhangi ipuçları alamadım.
$ gcc -s -W -Wall -Os -o ab ab.c
Adım 2: Programı çalıştırın ve iki numaradan birini girin.
$ ./ab a: 123 a = 123 b: _
Adım 3: İşlemi bulun.
$ ps aux | grep ab roland 21601 0.0 0.0 3648 456 pts/11 S+ 15:17 0:00 ./ab roland 21665 0.0 0.0 5132 672 pts/12 S+ 15:18 0:00 grep ab
Adım 4: İşlemciye bir hata ayıklayıcı ekleyin (21601). o main
fonksiyonu ve scanf
işlevini çağırarak bazı kodu arasında olduğundan
$ gdb ... (gdb) attach 21601 ... (gdb) where #0 0x00007fdecfdd2970 in read() from /lib/libc.so.6 #1 0x00007fdecfd80b40 in _IO_file_underflow() from /lib/libc.so.6 #2 0x00007fdecfd8230e in _IO_default_uflow() from /lib/libc.so.6 #3 0x00007fdecfd66903 in _IO_vfscanf() from /lib/libc.so.6 #4 0x00007fdecfd7245c in scanf() from /lib/libc.so.6 #5 0x0000000000400570 in ??() #6 0x00007fdecfd2f1a6 in __libc_start_main() from /lib/libc.so.6 #7 0x0000000000400459 in ??() #8 0x00007fffd827da48 in ??() #9 0x000000000000001c in ??() #10 0x0000000000000001 in ??() #11 0x00007fffd827f9a2 in ??() #12 0x0000000000000000 in ??()
ilginç kare, sayı 5, bu nedenle bizim main
işlev olmalıdır.
(gdb) frame 5 ... (gdb) disassemble $pc $pc+50 ... 0x0000000000400570 : test %eax,%eax 0x0000000000400572 : jle 0x40058c <[email protected]+372> 0x0000000000400574 : mov 0x2003fe(%rip),%edx # 0x600978 <[email protected]+2098528> 0x000000000040057a : mov 0x2003fc(%rip),%esi # 0x60097c <[email protected]+2098532> 0x0000000000400580 : mov $0x40068f,%edi 0x0000000000400585 : xor %eax,%eax 0x0000000000400587 : callq 0x4003f8 <[email protected]> ...
Şimdi fonksiyon printf
üç parametre alacak biliyorum ve orada iki sadece dört bayt birbirlerinden uzak şunlardır: ayıklama oturumu devam ediliyor. Bu ikisinin a
ve b
değişkenlerimiz olduğuna dair iyi bir işaret. Yani a
adresi 0x600978 veya 0x60097c'dir. en deneyerek öğrenelim: 0x0000007b (girdiğimiz 123 için onaltılık gösterimi, çünkü) ve b
0x600978 olan
(gdb) x/w 0x60097c 0x60097c <[email protected]+2098532>: 0x0000007b (gdb) x/w 0x600978 0x600978 <[email protected]+2098528>: 0x00000000
Yani a
Hata ayıklayıcısında, şimdi a
değişkenini değiştirebilir ve sonra programa devam edebiliriz. iki sayıyı girmek istedi programda
(gdb) set *(int *)0x60097c = 1234567 (gdb) continue
Arka:
$ ./ab a: 123 a = 123 b: 5 a = 1234567, b = 5 $
Bu fiziksel adresinizi değil, fiziksel adresinizi verir. –
olarak kısmen önce cevap normal programlar bunlar sanal bir adres alanı ile çalıştırmak gibi fiziksel adresler hakkında endişelenmenize gerek olmamalıdır tüm kolaylıkları. Ayrıca, her sanal adres fiziksel bir adrese sahip değildir, haritalanmış dosyalara veya değiştirilmiş sayfalara ait olabilir. Ancak, bazen bu haritalamayı, kullanıcı alanında bile görmek ilginç olabilir.
Bu amaçla, Linux çekirdeği, eşlemeyi /proc
'daki bir dosya kümesinden kullanıcı sayfasına çıkarır. Dökümantasyon here bulunabilir. Kısa özet:
/proc/$pid/maps
böyle eşleştirilmiş dosyalar için gelen dosya olarak birlikte ek bilgilerle sanal adreslerin eşleme listesi sağlar./proc/$pid/pagemap
, varsa fiziksel adres de dahil olmak üzere, eşlenen her sayfa hakkında daha fazla bilgi sağlar.
This website, bu arabirimi kullanarak tüm çalışan işlemlerin eşlemelerini dökülen bir C programı ve ne yaptığını açıklayan bir C programı sunar.
Testlerle en az örnek: https://stackoverflow.com/questions/17021214/how-to-decode-proc-pid-pagemap-entries-in-linux/45126141#45126141 –
#include "stdio.h"
#include "unistd.h"
#include "inttypes.h"
uintptr_t vtop(uintptr_t vaddr) {
FILE *pagemap;
intptr_t paddr = 0;
int offset = (vaddr/sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
uint64_t e;
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
if (e & (1ULL << 63)) { // page present ?
paddr = e & ((1ULL << 54) - 1); // pfn mask
paddr = paddr * sysconf(_SC_PAGESIZE);
// add offset within page
paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
}
}
}
fclose(pagemap);
}
return paddr;
}
- 1. Bir JavaScript değişkeninin hafıza adresini nasıl alabilirim?
- 2. CPU, belirli bir fiziksel bellek adresini nerede arayacağını biliyor?
- 3. Django kullanıcı e-posta adresini güncelle
- 4. Kullanıcı e-posta adresini twitter'dan nasıl alabilirim oAuth?
- 5. phpmyadmin'den mySQL sunucusu ip adresini nasıl bulurum?
- 6. Geçerli DNS sunucusunu nasıl bulabilirim?
- 7. Bir işaretçinin adresini bulma
- 8. Linux'taki mmap'ed fiziksel belleği için kullanıcı alanında yetersiz performans
- 9. Sunucumun IP adresini PHP (CLI)
- 10. Bir koşul değişkeninin işaretlenmesi (pthreads)
- 11. bir dize adresini gösteriliyor
- 12. Bir mutex değişkeninin bir while döngüsünde işlenmesi
- 13. Ip adresini uzak bir makineden nasıl edinirsiniz?
- 14. printf bir yapının adresini görmek nasıl
- 15. Bir char dizisindeki öğelerin adresini nasıl alabilirim?
- 16. cpu gerçek modda 20-bit adresini nasıl hesaplar
- 17. Oracle'da bir nesnenin OWNER öğesini nasıl bulabilirim?
- 18. D3 fiziksel yerçekimi
- 19. İki değişken değişkeninin eşitliği
- 20. Mac'te görünen adından bir yazı tipinin tam yolunu nasıl bulabilirim?
- 21. Bir maven profilinde bir sistem değişkeninin ayarlanması
- 22. lldb: Bir değişkenin adresini yazdırma
- 23. Kullanıcı Aracısı ve Global IP adresini Python kullanarak bulma
- 24. iPhone'da nasıl yazılabilir bir yol bulabilirim?
- 25. Android ListView Bağdaştırıcısında bir String değişkeninin saklanması
- 26. Fiziksel cihazı Notebook'a bağlama
- 27. (SalesOrderEntity'den) nasıl gönderim adresini alabilirim?
- 28. javascript'te ipv6 adresini nasıl şeritleyebilirim?
- 29. Bir oturum değişkeninin tutabileceği maksimum boyut nedir?
- 30. Bir URL'ye url adresini göster
Muhtemelen/dev/mem? – user2284570
http://stackoverflow.com/questions/5748492/is-there-any-api-for-determining-the-physical-address-from-virtual-address-in-li –