막후: 전역 포인터에 값을 부여하여 리:C Hello World의 어셈블리 출력에 대한 모든 줄의 의미는 무엇입니까?

안녕하세요!
이것은 이 시리즈의 다섯 번째 편이다.만약 네가 아직 이 시리즈의 앞문장을 읽지 않았다면, 나는 네가 읽기를 건의한다. 왜냐하면 이 문장은 앞문장의 기초 위에서 앞문장에서 해석한 세부 사항을 뛰어넘었기 때문이다.
나는 이 글을 쓰는 과정에서 이 모든 것을 이해했다. 만약 당신이 어떤 잘못을 발견하거나 어떤 건의와 개선이 있다면 평론에 알려 주십시오.
본고에서, 우리는 c 파일에 부여된 값을 가진 전역 포인터를 어셈블리로 전환하는 방법을 보게 될 것이다.

포인터


바늘은 변수일 뿐 다른 변수의 주소를 저장합니다.체인 시계 바늘도 사용할 수 있다. 이것은 때때로 C 언어에서 체인 시계를 실현하는데, 우리는 그 중에서 변수의 위치를 저장하고, 변수 자체는 다른 변수의 위치를 포함한다.이를 포인터를 가리키는 포인터라고 합니다.
앞의 글에서 우리는 인트,float,char 등 간단한 전역 변수에 값을 분배하는 방법을 보았고, 바늘에 분배된 값을 어셈블리로 전환하는 방법을 보았다.

단순 글로벌 포인터


간단한 예를 먼저 보도록 하겠습니다.
int *a = 5;
이것은 유효한 코드가 아닙니다. 값 5를 저장하려고 하기 때문에 코드의 어느 위치든 가리킬 수 있습니다. 데이터 세그먼트에서 시작하는 6바이트, 심지어 코드 세그먼트를 가리킬 수도 있습니다. 이 값에 접근하는 주 함수를 추가하면 세그먼트 오류로 인해 붕괴됩니다.
생성된 코드를 보여드릴게요.😄
    .globl  a
    .data
    .align 8
    .type   a, @object
    .size   a, 8
a:
    .quad   5
그 중 대부분은 전역 변수와 유사하지만 크기는 8바이트이다. 내가 그것을 컴파일한 기계는 64비트이기 때문에 모든 주소는 64비트, 즉 8바이트이다.
또 다른 차이점은 변수 a에 저장된 값이다. 예를 들어.quad 5..quad 8바이트의 값을 저장하고 5바이트의 값을 저장하는 데 사용됩니다.
이제 실질적인 예를 하나 보도록 하겠습니다.
int a =5;
int *b = &a;
이것은 프로그램 집합을 생성할 것이다
    .globl  a
    .data
    .align 4
    .type   a, @object
    .size   a, 4
a:
    .long   5
    .globl  b
    .section    .data.rel.local,"aw"
    .align 8
    .type   b, @object
    .size   b, 8
b:
    .quad   a
성명 변수 a의 첫 번째 부분은 이전 글에서 설명한 것과 같다.
두 번째 부분은 .globl b부터 시작하여 b를 전역 변수로 성명한다..section 프로그램의 섹션을 설명하는 데 사용되며, 이 섹션은 읽기와 쓰기 등 특정한 권한을 부여받을 수 있습니다. .section .data.rel.local,"aw" 어셈블러에게 다음 섹션을 하나의 섹션으로 편집하라고 알려 줍니다.데이터레이.local, 다시 지정할 수 있는 데이터를 저장합니다.이것은 현재 프로그램 집합 파일에서 이 데이터에 대한 모든 언급은 탭을 통해 이루어진다는 것을 의미한다. 링크가 이 파일을 잠시 후에 링크할 때, 이 절은 현재 위치에서 다른 위치로 이동하고, 그 후에만 링크가 주소를 계산하고 교체해야 하기 때문이다.
"aw"는 섹션의 유형을 지정합니다. 그 중에서 a는 할당할 수 있음을 표시하고, 실행할 때 이 섹션에 공간을 보존해야 한다는 것을 표시합니다.할당할 수 없는 부분은 실행할 때 디버깅 데이터를 포함하는 부분과 같은 공간을 할당할 필요가 없다."w"는 이 부분은 쓸 수 있고, 은식은 읽을 수 있음을 나타낸다.
그런 다음 b의 정렬, 유형 및 치수를 정의합니다.여기에 저장된 값은 .quad a 어셈블러가 계산한 것이 아니라 링크가 이 파일을 잠시 후에 연결할 때 계산한 것이다.이 때 링크는 전체 실행 가능한 파일에서 탭 a의 주소를 확인한 다음 모든 이벤트로 바꿉니다.
만약 우리가 b 다음에 다른 변수를 정의한다면,
int a = 5;
int *b = &a;
int c = 5;
assembly에서 변수 c를 설명하기 전에 .data를 사용하여 다시 섹션을 전환합니다.
    .globl  b
    .section    .data.rel.local,"aw"
    .align 8
    .type   b, @object
    .size   b, 8
b:
    .quad   a
    .globl  c
    .data
    .align 4
    .type   c, @object
    .size   c, 4
c:
    .long   5
float, double, single char의 지침은 위와 같다.
문자열에 대한 문자 포인터를 정의할 때 다음을 수행합니다.
char *a = "Hello";
프로그램 세트가 다음과 같이 변경되었습니다.
    .globl  a
    .section    .rodata
.LC0:
    .string "Hello"
    .section    .data.rel.local,"aw"
    .align 8
    .type   a, @object
    .size   a, 8
a:
    .quad   .LC0
여기에 .globl a 이후 한 절이 .section .rodata로 변경되어 아래의 데이터를 읽기 전용 데이터 절에 두어야 한다는 것을 나타낸다.다음은 라벨.LC0이다.
내 대답에 따르면,

대답: C Hello World의 어셈블리 출력의 줄마다 무슨 뜻입니까?


2016년 7월 10일.
22

다음은 @Thomas Pornin 답안에 대한 보충입니다.
  • .LC0 문자열 문자와 같은 부분 상수입니다.
  • .LFB0 로컬 함수 시작
  • .LFE0 로컬 함수 끝
  • 이 탭들의 접미사는 0부터 시작하는 숫자입니다.
    이것은 gcc 어셈블리 프로그램의 관례이다.
    Open Full Answer
    LC는 로컬 상수, 0은 상수의 개수를 나타냅니다.이후 앞의 글에서 보듯이 .string 명령을 사용하여 문자열을 저장합니다. 이것은 기본적으로 문자열이 0 바이트로 끝난다는 것을 의미합니다.
    그런 다음 섹션을 .data.rel.local로 다시 변경한 다음 이 상수의 레이블 LC0을 포인터 값에 저장합니다.

    정적 글로벌 포인터


    일반 변수를 가리키는 정적 유형 지침, 정적 점 변수를 가리키는 일반 지침과 정적 변수를 가리키는 정적 지침은 각 변수에 부족한 .globl를 제외하고는 모두 일반 변수와 유사하다
    int a = 5;
    static int *b = &a;
    
    b에 잃어버린 것이 하나 있을 것이다.globl.
    static int a = 5;
    int *b = &a;
    
    .globl명이 실종되고,
    static int a = 5;
    static int *b = &a;
    
    둘 다 잃어버릴 것이다.globl.

    글로벌 상수 포인터


    우선 비상량 변수를 가리키는 상수 지침을 살펴보자.
    int a =5;
    const int *b = &a;
    int g = 5;
    
    놀랍게도, 이것은 생성된 프로그램 집합에 대해 어떠한 변경도 할 수 있고, 작성을 멈추지 않을 것이다
    void main(){
         b = &g;
    }
    
    그것은 컴파일하고 실행할 때 아무런 오류도 없었다.
    하지만
    void main(){
         *b = &g;
    }
    
    다음과 같이 컴파일 시 오류가 발생합니다.
    global_assg.c: In function ‘main’:
    global_assg.c:5:18: error: assignment of read-only location ‘*b’
        5 | void main() { *b = g; }
          |  
    
    즉 상수 바늘은 그것을 사용하지 않고 그것이 가리키는 값을 수정한다.우리는 a를 직접 사용하여 a의 값을 바꿀 수 있지만 *b = something;로 a의 값을 바꿀 수 없다
    상수 솔리드에 대한 일반 포인터:
    const int a =5;
    int *b = &a;
    
    컴파일 시 경고가 생성됩니다.
    global_assg.c:2:10: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
        2 | int *b = &a;
          |
    
    그래도 편집할 줄 알아요.a 자체가 상수이기 때문에 로데이터 섹션에 놓여 있기 때문에 using *b = something; 의 값을 변경하려는 시도는 실행 시 단락 오류를 초래할 수 있습니다.
    const a = 5;
    const int *b = &a;
    
    상수 변수에 대한 상수 포인터를 컴파일할 때 경고나 오류가 없습니다.

    전역 배열 포인터


    포인터 배열에서 다음을 수행합니다.
    int b,c,d;
    int *a[] = {&b,&c,&d};
    
    어셈블리:
        .globl  a
        .section    .data.rel.local,"aw"
        .align 16
        .type   a, @object
        .size   a, 24
    a:
        .quad   b
        .quad   c
        .quad   d
    
    이것은 바늘과 수조의 결과입니다. 바늘과 같은 부분에 놓여 있지만, 수조와 같고, 크기는 3개의 바늘이며, 8*3=24바이트입니다.이 값들은 d, c, d의 라벨로 저장됩니다.
    그룹에 static를 추가하면 위에서 삭제.globl만 하고, 그룹에 const를 추가하면 그룹을 통해 값을 부여하는 모든 코드*a[1] = something;의 컴파일을 막을 수 있습니다.const의 다른 조합이 제시한 결과는 위에서 언급한 비수 그룹 지침과 유사합니다.

    포인터 대 포인터


    이런 코드.
    int a =5;
    int *b = &a;
    int **c = &b;
    
    a와 b의 어셈블러 코드는 이전과 같으며 c의 어셈블러 코드는 다음과 같이 생성됩니다.
        .globl  c
        .align 8
        .type   c, @object
        .size   c, 8
    c:
        .quad   b
    
    여기서 c 값에는 태그 b가 사용됩니다.
    이것은 c에서 컴파일할 때 전역에서 지정한 바늘을 어셈블리로 바꾸는 방식입니다.
    다시 한 번, 나는 이 글을 쓸 때 이 모든 것을 배웠다. 만약 당신이 어떤 잘못이나 건의와 개선이 있다면, 평론에서 나에게 알려주십시오.
    감사합니다!
    노트:

  • This 맞습니다.데이터rel 부분.

  • This는 이동 가능한 구간이 무엇인지 잘 설명했다.

  • This는 할당 및 로드 가능 섹션에 대한 간략한 설명입니다.
  • 이 동영상은 ELF 파일과 그 중의 부분과 부분을 잘 설명한다. https://youtu.be/nC1U1LJQL8o
  • 좋은 웹페이지 즐겨찾기