如何在C中实现只读存储器?

时间:2022-09-11 16:48:20

I heard that in C, if I do

我在C中听到过,如果我知道的话

char *s = "hello world". 

the "hello world" is actually stored in read-only memory.

“hello world”实际上存储在只读内存中。

I am not so clear about read-only memory. What is the explanation? Is that like a flag to the compiler that tells the compiler to do not write into that section?

我对只读记忆不是很清楚。解释是什么?这是否像编译器的标志,告诉编译器不要写入那个部分?

7 个解决方案

#1


28  

That's not a feature of the C language but a feature of the compiler/linker and the operating system working together.

这不是C语言的特性,而是编译器/链接器和操作系统协同工作的特性。

When you compile such code the following happens:

当您编译这些代码时,会发生以下情况:

  • The compiler will put the string into a read-only data-section.

    编译器将把字符串放入只读数据段。

  • The linker collects all the data in such read-only sections and puts them into a single segment. This segment resides in the executable file and is flagged with a "read only"-attribute.

    链接器收集这些只读部分中的所有数据,并将它们放入单个段中。此段驻留在可执行文件中,并用“只读”属性标记。

  • Now comes the operating system executable loader. It loads the executable (or maps it into memory to be more exact). Once this is done, the loader walks the sections and sets access-permissions for each segment. For a read-only data segment it will most likely disable code-execute and write access. Code (for example, your functions) gets execute rights but no write access. Ordinary data like static variables gets read and write access and so on...

    现在出现了操作系统可执行加载程序。它加载可执行文件(或者将其映射到内存中以便更精确)。完成后,加载程序遍历各节并为每个段设置访问权限。对于只读数据段,它很可能禁用代码执行和写入访问。代码(例如,您的函数)获得执行权限,但没有写访问。像静态变量这样的普通数据会被读写访问等等……

That's how modern operating systems do it.

这就是现代操作系统的运作方式。

As said, it's not a feature of the C language. If you compile the same problem for DOS, for example, the program will run but no write protection would be possible, because the DOS-loader does not know about read-only sections.

如前所述,它不是C语言的一个特性。例如,如果您为DOS编译相同的问题,那么程序将会运行,但是不可能有写保护,因为DOS加载程序不知道只读部分。

#2


6  

Executables contain two parts: a .data section, containing global variables, and a .text section, containing the actual machine code.

可执行文件包含两部分:包含全局变量的.data部分和包含实际机器代码的.text部分。

Strings are placed into the .data section. What C does when it sees "Hello world" is it puts the string "Hello world" into the executable itself, and replaces instance of "Hello world" in the program with the address where that string ends up being loaded.

字符串被放在.data部分。C在看到“Hello world”时所做的是将字符串“Hello world”放入可执行文件本身,并将程序中的“Hello world”实例替换为该字符串最终被加载的地址。

Having said that, I'm not sure why it's read-only - theoretically a program should be able to modify its own memory..

话虽如此,我不确定为什么它是只读的——理论上一个程序应该能够修改它自己的内存。

#3


3  

True read-only memory is implemented by the memory subsystem of the OS. The OS can mark certain pages as read-only.

真正的只读内存是由OS的内存子系统实现的。操作系统可以将某些页面标记为只读。

In the binary, the compiler can tell the OS which parts of the executable should be placed in read-only vs read-write memory pages.

在二进制中,编译器可以告诉操作系统哪些部分的可执行文件应该被放置在只读和读写内存页中。

#4


2  

An example of how to do this in Linux is on page 179 of Advanced Linux Programming by Mark Mitchell, Jeffrey Olham, and Alex Samuel.

关于如何在Linux中实现这一点的一个例子是Mark Mitchell、Jeffrey Olham和Alex Samuel的高级Linux编程的第179页。

#5


1  

As other folks have mentioned, whether the contents of constant strings are stored in read-only memory is determined by the operating system, compiler, and chip architecture.

正如其他人提到的,常量字符串的内容是否存储在只读存储器中是由操作系统、编译器和芯片体系结构决定的。

More precisely, the C standard specifies that the quoted strings are considered to have "const char[]" type (or words to that effect, I don't have the standard at hand).

更准确地说,C标准指定引用的字符串被认为具有“const char[]”类型(或者类似的词,我手头没有标准)。

Any code that attempts to modify the contents of such a string is invoking undefined behavior. That means that literally anything can happen at that point, and the provider of the compiler isn't even required to document what can happen.

任何试图修改此类字符串内容的代码都在调用未定义的行为。这意味着,在这一点上任何事情都可能发生,编译器的提供者甚至不需要记录可能发生的事情。

In practice, this means that a C or C++ program that wants to be portable has to avoid modifying constant strings.

在实践中,这意味着希望可移植的C或c++程序必须避免修改常量字符串。

In general, the compiler will not allow you to modify the contents of of "const" variables, so you can consider "const" to mean "read only" in most cases. Unfortunately, there's a special exception for char * and const char *, largely for historical reasons. That means that code like this:

一般来说,编译器不允许您修改“const”变量的内容,因此您可以考虑在大多数情况下“const”表示“只读”。不幸的是,由于历史原因,char *和const char *有一个特殊的例外。这意味着像这样的代码:

char *x = "Hello, World";
*x = 'h';

will compile without error or warning, even though it invokes undefined behavior.

即使它调用了未定义的行为,也会在没有错误或警告的情况下编译。

#6


0  

You could try something like

你可以试试

s[4] = '0';

and see if it says "hello w0rld" when you call

你打电话的时候,看看上面是不是写着“你好,w0rld”

puts(s);

If it causes an immediate Segmentation Fault or a Data Execution Prevention exception then it is probably read only. (If the system lets you get away with it, that doesn't make it a good idea.)

如果它导致立即的分割错误或数据执行防止异常,那么它很可能是只读的。(如果这个系统让你侥幸过关,那就不是个好主意。)

#7


0  

When you write char s[10]="sneha"; you are allocating 10 bytes of storage space(not memory, memory comes into picture only when u r executing your program) in your object file. This is static allocation of memory( at compile time).

当你写char s[10]="sneha"时;在对象文件中分配10字节的存储空间(不是内存,内存只有在ur执行程序时才会出现)。这是内存的静态分配(在编译时)。

But when you write char *s="sneha"; you are not allocating any storage space to store "sneha". It will get stored in READ ONLY section. But the pointer s is stored in different section based on where it is declared. But it is pointing to the READ ONLY DATA "sneha". So if you try to write on it you will get segmentation fault.

但是当你写char *s="sneha"时;您没有分配任何存储空间来存储“sneha”。它将存储在只读部分。但是根据声明的位置,指针s存储在不同的部分中。但它指向的是只读的数据“sneha”。如果你试着写它,你会得到分割错误。

For example:

例如:

char *s[10]="sneha";
s[1]="N"; 
printf("%s",s);  // you expecting output sNeha, 
                 // but you get a seg fault since it is ONLY DATA 

#1


28  

That's not a feature of the C language but a feature of the compiler/linker and the operating system working together.

这不是C语言的特性,而是编译器/链接器和操作系统协同工作的特性。

When you compile such code the following happens:

当您编译这些代码时,会发生以下情况:

  • The compiler will put the string into a read-only data-section.

    编译器将把字符串放入只读数据段。

  • The linker collects all the data in such read-only sections and puts them into a single segment. This segment resides in the executable file and is flagged with a "read only"-attribute.

    链接器收集这些只读部分中的所有数据,并将它们放入单个段中。此段驻留在可执行文件中,并用“只读”属性标记。

  • Now comes the operating system executable loader. It loads the executable (or maps it into memory to be more exact). Once this is done, the loader walks the sections and sets access-permissions for each segment. For a read-only data segment it will most likely disable code-execute and write access. Code (for example, your functions) gets execute rights but no write access. Ordinary data like static variables gets read and write access and so on...

    现在出现了操作系统可执行加载程序。它加载可执行文件(或者将其映射到内存中以便更精确)。完成后,加载程序遍历各节并为每个段设置访问权限。对于只读数据段,它很可能禁用代码执行和写入访问。代码(例如,您的函数)获得执行权限,但没有写访问。像静态变量这样的普通数据会被读写访问等等……

That's how modern operating systems do it.

这就是现代操作系统的运作方式。

As said, it's not a feature of the C language. If you compile the same problem for DOS, for example, the program will run but no write protection would be possible, because the DOS-loader does not know about read-only sections.

如前所述,它不是C语言的一个特性。例如,如果您为DOS编译相同的问题,那么程序将会运行,但是不可能有写保护,因为DOS加载程序不知道只读部分。

#2


6  

Executables contain two parts: a .data section, containing global variables, and a .text section, containing the actual machine code.

可执行文件包含两部分:包含全局变量的.data部分和包含实际机器代码的.text部分。

Strings are placed into the .data section. What C does when it sees "Hello world" is it puts the string "Hello world" into the executable itself, and replaces instance of "Hello world" in the program with the address where that string ends up being loaded.

字符串被放在.data部分。C在看到“Hello world”时所做的是将字符串“Hello world”放入可执行文件本身,并将程序中的“Hello world”实例替换为该字符串最终被加载的地址。

Having said that, I'm not sure why it's read-only - theoretically a program should be able to modify its own memory..

话虽如此,我不确定为什么它是只读的——理论上一个程序应该能够修改它自己的内存。

#3


3  

True read-only memory is implemented by the memory subsystem of the OS. The OS can mark certain pages as read-only.

真正的只读内存是由OS的内存子系统实现的。操作系统可以将某些页面标记为只读。

In the binary, the compiler can tell the OS which parts of the executable should be placed in read-only vs read-write memory pages.

在二进制中,编译器可以告诉操作系统哪些部分的可执行文件应该被放置在只读和读写内存页中。

#4


2  

An example of how to do this in Linux is on page 179 of Advanced Linux Programming by Mark Mitchell, Jeffrey Olham, and Alex Samuel.

关于如何在Linux中实现这一点的一个例子是Mark Mitchell、Jeffrey Olham和Alex Samuel的高级Linux编程的第179页。

#5


1  

As other folks have mentioned, whether the contents of constant strings are stored in read-only memory is determined by the operating system, compiler, and chip architecture.

正如其他人提到的,常量字符串的内容是否存储在只读存储器中是由操作系统、编译器和芯片体系结构决定的。

More precisely, the C standard specifies that the quoted strings are considered to have "const char[]" type (or words to that effect, I don't have the standard at hand).

更准确地说,C标准指定引用的字符串被认为具有“const char[]”类型(或者类似的词,我手头没有标准)。

Any code that attempts to modify the contents of such a string is invoking undefined behavior. That means that literally anything can happen at that point, and the provider of the compiler isn't even required to document what can happen.

任何试图修改此类字符串内容的代码都在调用未定义的行为。这意味着,在这一点上任何事情都可能发生,编译器的提供者甚至不需要记录可能发生的事情。

In practice, this means that a C or C++ program that wants to be portable has to avoid modifying constant strings.

在实践中,这意味着希望可移植的C或c++程序必须避免修改常量字符串。

In general, the compiler will not allow you to modify the contents of of "const" variables, so you can consider "const" to mean "read only" in most cases. Unfortunately, there's a special exception for char * and const char *, largely for historical reasons. That means that code like this:

一般来说,编译器不允许您修改“const”变量的内容,因此您可以考虑在大多数情况下“const”表示“只读”。不幸的是,由于历史原因,char *和const char *有一个特殊的例外。这意味着像这样的代码:

char *x = "Hello, World";
*x = 'h';

will compile without error or warning, even though it invokes undefined behavior.

即使它调用了未定义的行为,也会在没有错误或警告的情况下编译。

#6


0  

You could try something like

你可以试试

s[4] = '0';

and see if it says "hello w0rld" when you call

你打电话的时候,看看上面是不是写着“你好,w0rld”

puts(s);

If it causes an immediate Segmentation Fault or a Data Execution Prevention exception then it is probably read only. (If the system lets you get away with it, that doesn't make it a good idea.)

如果它导致立即的分割错误或数据执行防止异常,那么它很可能是只读的。(如果这个系统让你侥幸过关,那就不是个好主意。)

#7


0  

When you write char s[10]="sneha"; you are allocating 10 bytes of storage space(not memory, memory comes into picture only when u r executing your program) in your object file. This is static allocation of memory( at compile time).

当你写char s[10]="sneha"时;在对象文件中分配10字节的存储空间(不是内存,内存只有在ur执行程序时才会出现)。这是内存的静态分配(在编译时)。

But when you write char *s="sneha"; you are not allocating any storage space to store "sneha". It will get stored in READ ONLY section. But the pointer s is stored in different section based on where it is declared. But it is pointing to the READ ONLY DATA "sneha". So if you try to write on it you will get segmentation fault.

但是当你写char *s="sneha"时;您没有分配任何存储空间来存储“sneha”。它将存储在只读部分。但是根据声明的位置,指针s存储在不同的部分中。但它指向的是只读的数据“sneha”。如果你试着写它,你会得到分割错误。

For example:

例如:

char *s[10]="sneha";
s[1]="N"; 
printf("%s",s);  // you expecting output sNeha, 
                 // but you get a seg fault since it is ONLY DATA