[독서 노트] 프로그래머 의 자기 수양 총화 (5)

5480 단어
[독서 노트] 프로그래머 의 자기 수양 총화 (5)
성명: 인용 출처 를 밝 혀 주 십시오.http://blog.csdn.net/lg1259156776/
설명: 프로그래머 의 자기 수양 이라는 책의 독서 총화 로 읽 기 가 추진 되면 서 내용 이 점점 늘 어 나 고 있다.
COMMON 블록
앞에서 언급 한 강약 기호 체 제 는 같은 기호의 정 의 를 여러 파일 에 존재 하도록 허용 한다. 컴 파일 러 는 변수 데이터 형식 을 알 고 링크 기 는 데이터 형식 을 모른다. 즉, 변수 유형 은 링크 기 에 대해 투명 하고 하나의 기호의 이름 만 알 고 유형 이 일치 하 는 지 모른다.여러 종류의 일치 하지 않 는 기 호 를 정의 할 때 링크 기 는 어떻게 처리 해 야 합 니까?
한 가지 상황 은 두 개의 강 한 기호 이다. 물론 직접 링크 기 가 잘못 되 었 고 강 한 기호 가 다 중 정 의 를 내 릴 수 없다.두 가지 상황 은 강 한 기호 이 고 나머지 는 약 한 기호 이다.데이터 형식의 공간 이 크 든 강 한 기호 만 선택 할 것 이다.세 가지 상황 은 여러 개의 약 한 기호 로 데이터 형식 을 선택 하여 메모리 공간 에서 가장 큰 정 의 를 차지 합 니 다.
컴 파 일 러 가 하나의 컴 파 일 러 를 대상 파일 로 컴 파일 할 때 컴 파 일 러 가 약 한 기 호 를 포함 하면 약 한 기호 가 최종 적 으로 공간 크기 를 차지 하 는 것 은 알 수 없다. 다른 컴 파 일 러 에서 이 약 한 기호 가 차지 하 는 공간 크기 를 모 르 기 때문에 컴 파 일 러 는 이 약 한 기 호 를 BSS 세그먼트 에 공간 을 분배 할 수 없다. 필요 한 공간 크기 는 알 수 없 기 때문이다.그러나 링크 기 는 링크 과정 에서 약 한 기호의 크기 를 확인 할 수 있 습 니 다. 링크 기 가 모든 입력 대상 파일 을 읽 은 후에 약 한 기호의 최종 크기 를 확인 할 수 있 기 때문에 최종 출력 파일 의 bss 세그먼트 에서 공간 을 분배 할 수 있 습 니 다.전체적으로 초기 화 되 지 않 은 전역 변 수 는 결국 BSS 세그먼트 에 놓 여 있 습 니 다.
여기 서 다시 한 번 설명 하 겠 습 니 다. 전역 변 수 를 초기 화하 지 않 은 것 은 대상 파일 에 공간 을 할당 하지 않 았 습 니 다. 위 에서 말 한 원인 때문에 초기 화 된 전역 변 수 는 강 한 기호 이 고 대상 파일 에 주 소 를 할당 하 였 습 니 다.
초기 C 언어 프로그래머 들 은 부주의 하여 extern 성명 변 수 를 사용 하 는 것 을 자주 잊 어 버 려 서 컴 파일 러 가 여러 대상 파일 에서 같은 변 수 를 정의 할 수 있 도록 했다.이 문 제 를 해결 하기 위해 컴 파일 러 와 링크 기 는 아예 초기 화 되 지 않 은 변 수 를 모두 COMMON 형식 으로 처리한다.
정적 연결 라 이브 러 리
예 를 들 어 전형 적 인 C 언어 버 전 Hello World 는 C 언어 표준 라 이브 러 리 printf 출력 문자열 을 사용 합 니 다. printf 함수 가 문자열 을 일련의 처리 한 후에 마지막 으로 시스템 API 를 호출 합 니 다. 각 운영 체제 에서 터미널 에 문자열 을 출력 하 는 API 가 다 릅 니 다. Linux 다음 에는 write 시스템 호출 이 고 windows 다음 에는 writeConsole 시스템 API 입 니 다.
정적 라 이브 러 리 는 대상 파일 의 집합 으로 볼 수 있 습 니 다. 즉, 많은 대상 파일 이 압축 포장 을 거 쳐 파일 을 만 듭 니 다.AR 명령 이나 windows 의 lib. exe 를 사용 하여 lib 의 내용 을 만 들 고 추출 하 며 열거 합 니 다.
일반 라 이브 러 리 파일 의 대상 파일 간 에 도 서로 의존 하 는 경우 가 많 기 때문에 서로 의존 하 는 모든 대상 파일 을 인공 적 으로 찾 아 링크 하면 죽은 것 으로 추정 된다.그래서 링크 기 는 인공 을 대신 하여 이 일 을 처리 하고 필요 한 기호 와 대상 파일 을 자동 으로 찾 으 며 이 대상 파일 을 해당 하 는 라 이브 러 리 에서 압축 을 풀 어 실행 가능 한 파일 로 연결 합 니 다.
한 가지 제기 할 만 한 것 이 있 습 니 다. 왜 정적 링크 라 이브 러 리 에 있 는 대상 파일 은 하나의 함수 만 포함 합 니까?링크 기 는 정적 라 이브 러 리 를 연결 할 때 대상 파일 단위 입 니 다. 예 를 들 어 정적 라 이브 러 리 의 printf 함 수 를 참조 하면 링크 기 는 라 이브 러 리 에 printf 함 수 를 포함 하 는 대상 파일 을 연결 합 니 다. 만약 에 많은 함수 가 같은 대상 파일 에 넣 으 면 쓸모 없 는 함수 가 함께 출력 파일 에 연결 되 어 공간 낭 비 를 초래 할 수 있 습 니 다.그 러 니 필요 하지 않 은 함수 들 은 최종 출력 파일 에 연결 하지 마 세 요.
최소 프로그램
다음 과 같다.
char * str = "Hello world!
"; void print() { asm("movl $13, %%edx
\t" "movl %0, %%ecx
\t" "movl %0, %%ebx
\t" "movl %4, %%eax
\t" "int $0x80
\t" :: "r"(str):"edx","ecx","ebx"); } void exit() { asm("movl %42, %%ebx
\t" "movl %1, %%eax
\t" "int $0x80
\t"); } void nomain() { print(); exit(); }

소스 코드 를 분석 하고 프로그램 입 구 는 nomain () 함수 이 며 print 함 수 를 호출 하여 hello World 를 인쇄 한 다음 에 exit 함수 로 프로 세 스 를 끝 냅 니 다.이 print 는 Linux 의 Write 시스템 호출 을 사용 합 니 다. exit 는 EXIT 시스템 호출 을 사용 하고 GCC 의 내장 어 셈 블 리 를 사용 합 니 다.시스템 호출 은 0x 80 인 터 럽 트 를 통 해 이 루어 집 니 다. 그 중에서 eax 는 호출 번호, ebx, ecx, edx 등 유 니 버 설 레지스터 로 인 자 를 전달 합 니 다. 예 를 들 어 WRITE 호출 은 파일 핸들 에 데 이 터 를 기록 하 는 것 입 니 다. C 언어 원형 은 다음 과 같 습 니 다.
**int write(int filedesc, char * buffer, int size);**
  • WRITE 가 호출 한 호출 번호 4 는 eax = 4 이다.
  • filedesc 는 기 록 된 파일 핸들 을 표시 하고 ebx 레지스터 로 전달 하 며 기본 터미널 stdout 으로 출력 합 니 다. 핸들 은 0 이 므 로 ebx = 0 입 니 다.
  • buffer 는 캐 시 영역 주 소 를 기록 하고 ecx 레지스터 로 전달 하 며 출력 문자열 을 표시 하기 때문에 ecx = str.
  • size 는 쓰기 바이트 수 를 표시 하고 ex 레지스터 로 전달 하 며 문자열 의 길 이 는 13 바이트 이기 때문에 ex = 13 입 니 다.

  • 마찬가지 로 EXIT 시스템 호출 을 분석 할 수 있 습 니 다. ebx 는 프로 세 스 종료 코드 를 표시 합 니 다. 예 를 들 어 main 프로그램의 return 은 시스템 라 이브 러 리 에 되 돌아 가 고 시스템 라 이브 러 리 는 이 수 치 를 EXIT 시스템 호출 에 전달 합 니 다. 그러면 부모 프로 세 스 는 하위 프로 세 스 의 종료 코드 를 받 을 수 있 습 니 다. EXIT 시스템 호출 번 호 는 1 이기 때문에 eax = 1 입 니 다.
    첫 번 째 단 계 는 대상 파일 로 컴 파일 한 다음 ld 를 사용 하여 Tiny HelloWorld 로 연결 합 니 다. 명령 은 다음 과 같 습 니 다.
    gcc -c -fno-builtin TinyHelloWorld.c
    ld -static -e nomain -o TinyHelloWorld TinyHelloWorld.c
    

    설명: - fno - buildin gcc 가 제공 하 는 내장 함수 로 자주 사용 하 는 c 라 이브 러 리 함 수 를 컴 파일 러 내장 함수 로 교체 하여 최적화 기능 을 달성 합 니 다.이 기능 을 닫 기; -static 는 기본 동적 링크 형식 대신 정적 링크 를 표시 합 니 다. -e nomain 은 프로그램 입구 함수 가 nomain 임 을 나타 낸다.ELF 파일 헤더 의 e 에 대응entry 구성원 할당 은 nomain 함수 주소 입 니 다.
    objdump 또는 readlf 를 사용 하여 보 세 요. 네 개의 세그먼트 가 있 습 니 다. text, data, rodata,. coment.
    실제로 네 단락 은 모두 읽 기만 하 는 것 이 고 원칙적으로 한 단락 에 합 칠 수 있 으 며 이 단락 의 속성 은 읽 을 수 있 고 데이터 와 명령 을 포함 하 는 것 이다.
    링크 스 크 립 트
    사실 cmd 파일 과 유사 합 니 다. DSP 프로 그래 밍 개발 에서 매우 중요 한 내용 은 cmd 의 작성, 메모리 의 편성 입 니 다.
    ENTRY(nomain)
    SECTIONS
    {
        . = 0x08048000 + SIZEOF_HEADERS;
        tinytext : {*(.text) *(.data) *(.rodata)}
        /DISCARD/ : { *(.comment)}
    }
    

    아주 간단 한 링크 스 크 립 트 입 니 다. 첫 번 째 줄 은 nomain 을 지정 한 다음 에 첫 번 째 줄 은 할당 문 이 고 두 줄 은 세그먼트 변환 규칙 입 니 다.첫 번 째 문 구 는 현재 가상 주 소 를 0x 08048000 + SIZEOF 로 설정 합 니 다.HEADERS;매크로 는 출력 파일 의 파일 헤더 크기 입 니 다. "현재 가상 주 소 를 표시 합 니 다.tinytext 는 모든 단락 을 순서대로 이 단락 에 통합 합 니 다.마지막 설명 은. coment 세그먼트 를 무시 하고 파일 에 저장 하지 않 습 니 다.
    gcc -c -fno-builtin TinyHelloWorld.c
    ld -static -T TinyHelloWorld.lds -o TinyHelloWorld TinyHelloWorld.c
    

    2015 - 10 - 27 동아 일보

    좋은 웹페이지 즐겨찾기