programing

문자열 리터럴:그들은 어디로 갑니까?

copyandpastes 2022. 7. 17. 23:11
반응형

문자열 리터럴:그들은 어디로 갑니까?

스트링 리터럴을 할당/저장하는 위치에 관심이 있습니다.

여기서 흥미로운 을 하나 찾았어요.

스트링을 인라인으로 정의하면 실제로 프로그램 자체에 데이터가 포함되어 변경할 수 없습니다(일부 컴파일러는 스마트 트릭을 사용하여 이를 허용합니다).

하지만, 그것은 C++와 관련이 있었고, 귀찮게 하지 말라고 하는 것은 말할 것도 없습니다.

귀찮아.=D

그래서 내 질문은 내 문자열 리터럴은 어디에 어떻게 보관되느냐는 것이다.왜 바꾸려고 하면 안 되는 거죠?구현은 플랫폼에 따라 달라집니까?"스마트 트릭"에 대해 자세히 설명해 주실 분?

왜 바꾸려고 하면 안 되는 거죠?

정의되지 않은 동작이기 때문입니다.C99 N1256 드래프트 6.7.8/32 "초기화"에서 인용:

예 8: 선언

char s[] = "abc", t[3] = "abc";

"" objects ": "defined" char "defined" char 。s ★★★★★★★★★★★★★★★★★」t이치노

이 선언은 다음 선언과 동일합니다.

char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

어레이의 내용은 변경할 수 있습니다.한편, 선언문은

char *p = "abc";

정의하다p char of합니다.이의 요소는 리터럴type "to char"로됩니다.4번입니다.이 오브젝트의 요소는 문자열 리터럴로 초기화됩니다.「」를 하려고 했을 .p어레이의 내용을 수정하는 동작은 정의되어 있지 않습니다.

그들은 어디로 갑니까?

GCC 4.8 x86-64 ELF Ubuntu 14.04:

  • char s[]: "displaces"
  • char *s다음과 같습니다.
    • .rodata(섹션)
    • 로, '''가 있는 '입니다..text이과 Exec Write 이 없습니다.Exec은 이 권한이 없습니다.

프로그램:

#include <stdio.h>

int main() {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}

컴파일 및 디컴파일:

gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o

출력 내용:

 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata

되죠?.rodata★★★★★★ 。

그 후, 다음과 같이 입력합니다.

readelf -l a.out

내용(간소화):

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000704 0x0000000000000704  R E    200000

 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata

, ..text ★★★★★★★★★★★★★★★★★」.rodata할 수 변경할 수 없는 로 변환됩니다.Flags = R E하면 장애가 발생합니다. Linux 세그먼트 장애

char[]:

 char s[] = "abc";

입수처:

17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)

스택에 예:%rbp물론 수정할 수 있습니다.

일반적인 방법은 문자열 리터럴을 읽기 전용으로 프로세스 공간에 매핑되는 "읽기 전용 데이터" 섹션에 넣는 것입니다(이 때문에 변경할 수 없습니다).

플랫폼에 따라 다릅니다.예를 들어 단순한 칩 아키텍처는 읽기 전용 메모리 세그먼트를 지원하지 않으므로 데이터 세그먼트는 쓰기 가능합니다.

스트링 리터럴을 변경할 수 있는 방법(플랫폼에 따라 크게 달라지며 시간이 지남에 따라 변경될 수 있음)을 강구하기보다는 어레이를 사용합니다.

char foo[] = "...";

컴파일러는 어레이를 리터럴에서 초기화하도록 조정하며 사용자는 어레이를 수정할 수 있습니다.

이것에 대한 답은 아무도 없다.C 및 C++ 규격에서는 문자열 리터럴에는 정적 저장 기간이 있으며, 문자열 리터럴을 변경하려고 하면 정의되지 않은 동작이 발생하며, 동일한 내용을 가진 여러 문자열 리터럴이 동일한 스토리지를 공유할 수도 있고 공유할 수도 없는 경우도 있습니다.

쓰는 대상 시스템과 사용하는 실행 파일 형식의 기능에 따라 프로그램 코드가 텍스트 세그먼트에 저장되거나 초기화된 데이터를 위한 별도의 세그먼트가 있을 수 있습니다.

자세한 것은 플랫폼에 따라서도 다릅니다.대부분의 경우, 배치 장소를 알 수 있는 툴이 포함되어 있습니다.필요에 따라서, 그러한 상세도 제어할 수 있는 것도 있습니다(예를 들면, gnu ld는, 데이터나 코드등을 그룹화하는 방법을 모두 지정하는 스크립트를 제공할 수 있습니다).

문자열 리터럴은 읽기 전용 메모리에 할당되는 경우가 많기 때문에 고정됩니다.다만, 컴파일러에 따라서는, 「스마트 트릭」으로 변경할 수 있습니다.그리고 똑똑한 방법은 "메모리를 가리키는 문자 포인터를 사용하는 것"입니다.일부 컴파일러를 기억하십시오.이것이 허가되지 않을 수 있습니다.여기 데모입니다.

char *tabHeader = "Sound";
*tabHeader = 'L';
printf("%s\n",tabHeader); // Displays "Lound"

참고로, 다른 답변은 참고하겠습니다.

표준: ISO/IEC 14882:2003은 다음과 같습니다.

2.13 스트링 리터럴

  1. [...] 에는 [...]의배열하다n const charduration ( (3.7)" (3.7)

  2. 모든 문자열 리터럴이 구별되는지(즉, 오버랩되지 않는 오브젝트에 저장되는지) 여부는 구현에 따라 정의됩니다.문자열 리터럴을 수정하려고 했을 때의 효과는 정의되어 있지 않습니다.

는 gcc를 a로 ..rodata전용으로 .

CC++)cl.exe가됩니다..rdata를 참조해 주세요.

해서 나온 .dumpbin ★★★★★★★★★★★★★★★★★」objdump(Linux의 경우) 실행 파일의 섹션을 표시합니다.

예.

>dumpbin vec1.exe
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file vec1.exe

File Type: EXECUTABLE IMAGE

  Summary

        4000 .data
        5000 .rdata  <-- here are strings and other read-only stuff.
       14000 .text

실행 파일의 형식에 따라 다릅니다.어셈블리 프로그래밍의 경우 어셈블리 프로그램의 데이터 세그먼트에 문자열 리터럴을 넣을 수 있습니다.C 컴파일러도 이와 같은 기능을 하지만 이 모든 것은 컴파일 대상 시스템에 따라 달라집니다.

컴파일러마다 다를 수 있으므로 검색된 문자열 리터럴의 객체 덤프를 필터링하는 것이 가장 좋습니다.

objdump -s main.o | grep -B 1 str

어디에-s폭력objdump모든 섹션의 전체 내용을 표시합니다.main.o오브젝트 파일입니다.-B 1폭력grep또한 섹션 이름을 볼 수 있도록 일치 전에 한 줄을 인쇄합니다.str찾고 있는 문자열 리터럴입니다.

Windows 머신에 gcc가 있고, 에 선언된 변수가1개 있는 경우main맘에 들다

char *c = "whatever";

입니다.

objdump -s main.o | grep -B 1 whatever

돌아온다

Contents of section .rdata:
 0000 77686174 65766572 00000000           whatever....

언급URL : https://stackoverflow.com/questions/2589949/string-literals-where-do-they-go

반응형