Saya tertarik di mana string literal dialokasikan / disimpan.
Saya menemukan satu jawaban yang menarik di sini , dengan mengatakan:
Mendefinisikan inline string sebenarnya menyematkan data dalam program itu sendiri dan tidak dapat diubah (beberapa kompiler mengizinkan ini dengan trik pintar, jangan repot-repot).
Tapi, itu ada hubungannya dengan C ++, belum lagi dikatakan tidak repot.
Saya mengganggu. = D
Jadi pertanyaan saya adalah di mana dan bagaimana string string saya disimpan? Mengapa saya tidak mencoba mengubahnya? Apakah implementasinya bervariasi berdasarkan platform? Apakah ada yang peduli untuk menguraikan "trik pintar?"
sumber
foo = "hello"
dalam kasus ini) dapat menyebabkan efek samping yang tidak diinginkan ... (dengan asumsi Anda tidak kembali mengalokasikan memori dengannew
atau sesuatu)char *p = "abc";
untuk membuat string yang dapat berubah seperti dikatakan berbeda oleh @ChrisCooperTidak ada satu jawaban untuk ini. Standar C dan C ++ hanya mengatakan bahwa literal string memiliki durasi penyimpanan statis, setiap upaya untuk memodifikasinya memberikan perilaku yang tidak terdefinisi, dan beberapa string literal dengan konten yang sama mungkin atau mungkin tidak berbagi penyimpanan yang sama.
Bergantung pada sistem yang Anda gunakan untuk menulis, dan kemampuan format file yang dapat dieksekusi yang digunakannya, mereka dapat disimpan bersama dengan kode program di segmen teks, atau mereka mungkin memiliki segmen terpisah untuk data yang diinisialisasi.
Menentukan detail akan bervariasi tergantung pada platform juga - kemungkinan besar termasuk alat yang dapat memberi tahu Anda di mana meletakkannya. Beberapa bahkan akan memberi Anda kendali atas perincian seperti itu, jika Anda menginginkannya (mis. Gnu ld memungkinkan Anda untuk menyediakan skrip untuk menceritakan semuanya tentang cara mengelompokkan data, kode, dll.)
sumber
movb $65, 8(%esp); movb $66, 9(%esp); movb $0, 10(%esp)
untuk string"AB"
, tetapi sebagian besar waktu, itu akan berada di segmen non-kode seperti.data
atau.rodata
atau sejenisnya (tergantung pada apakah target mendukung atau tidak segmen hanya baca).Mengapa saya tidak mencoba mengubahnya?
Karena itu perilaku yang tidak terdefinisi. Kutipan dari C99 N1256 draft 6.7.8 / 32 "Inisialisasi" :
Kemana mereka pergi?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
char s[]
: tumpukanchar *s
:.rodata
bagian dari file objek.text
bagian dari file objek akan dibuang, yang memiliki izin Baca dan Exec, tetapi tidak TulisProgram:
Kompilasi dan dekompilasi:
Output berisi:
Jadi string disimpan di
.rodata
bagian tersebut.Kemudian:
Berisi (disederhanakan):
Ini berarti bahwa skrip linker default membuang keduanya
.text
dan.rodata
ke dalam segmen yang dapat dieksekusi tetapi tidak dimodifikasi (Flags = R E
). Mencoba untuk memodifikasi segmen seperti itu mengarah ke segfault di Linux.Jika kami melakukan hal yang sama untuk
char[]
:kami memperoleh:
jadi itu disimpan dalam tumpukan (relatif terhadap
%rbp
), dan tentu saja kita dapat memodifikasinya.sumber
FYI, hanya mencadangkan jawaban lainnya:
Standar: ISO / IEC 14882: 2003 mengatakan:
sumber
gcc membuat
.rodata
bagian yang dipetakan "di suatu tempat" di ruang alamat dan ditandai hanya baca,Visual C ++ (
cl.exe
) membuat.rdata
bagian untuk tujuan yang sama.Anda dapat melihat output dari
dumpbin
atauobjdump
(di Linux) untuk melihat bagian yang dapat dieksekusi.Misalnya
sumber
printf("some null terminated static string");
bukanprintf(*address);
di C)Itu tergantung pada format executable Anda . Salah satu cara untuk memikirkannya adalah bahwa jika Anda memprogram perakitan, Anda dapat menempatkan string literal di segmen data program perakitan Anda. Kompiler C Anda melakukan sesuatu seperti itu, tetapi semuanya tergantung pada sistem apa yang sedang Anda biner kompilasi.
sumber
Literal string sering dialokasikan ke memori hanya-baca, menjadikannya tidak berubah. Namun, dalam beberapa modifikasi kompiler dimungkinkan oleh "trik pintar" .. Dan trik pintar adalah dengan "menggunakan penunjuk karakter yang menunjuk ke memori" .. ingat beberapa kompiler, mungkin tidak mengizinkan ini..Ini adalah demo
sumber
Karena ini mungkin berbeda dari kompiler ke kompiler, cara terbaik adalah memfilter dump objek untuk string literal yang dicari:
di mana
-s
kekuatanobjdump
untuk menampilkan isi penuh dari semua bagian,main.o
adalah file objek,-B 1
memaksagrep
untuk juga mencetak satu baris sebelum pertandingan (sehingga Anda dapat melihat nama bagian) danstr
merupakan string literal yang Anda cari.Dengan gcc pada mesin Windows, dan satu variabel dinyatakan dalam
main
likeberlari
kembali
sumber