라벨이 컴파일러인 게시물 표시

C compiler & Program memory 구조

이미지
    <Main Memory로의 적재> D HDD에 저장된, 프로그래머가 작성한 소스코드가 전용 컴파일러에 의해 기계어 코드로 변환된다. 이 실행파일이 생성이 되고 실행된다면 Process가 생성되고 Process가 가지는 opened_file은 이 실행파일일 것이다. 위 단계부터 Main memory (RAM) 에 여러 정보들이 적재되기 시작한다.  이 적재도 무작정 순차적으로 되는 것이 아니라 위와 같은 메모리 구조를 따라서 적재된다. <Compile time & Run time> 변수 초기 데이터는 프로그래머가 지정한 초기값으로 초기화된 전역 변수로 main()함수가 실행되기 전 compile타임에 변수 초기 데이터가 복사되어 들어간다.  <선언과 할당> 만약 위 code에서 man이 선언된 후 man = {20, 'F', 'gordon'} 의 코드가 실행되면 이는 '선언'이 아니라 '할당'이다. <Const> const로 선언할 경우, 반드시 초기값이 존재해야한다. 선언 이후에 바뀔 수 없는 값이기 때문이다. <정적 변수 할당 시점> 정적 변수는 프로그램이 실행되기 전까지 존재하지 않는다. 프로그램 실행 후  | 정적 변수 할당 | main function으로의 돌입 executable file 자체는 변수가 아니며, 프로그램 실행시 executable code와 함께 Main Memory에 적재되어야 하는 데이터다. <Optimization> 프로그램이 특정 variable를 '절대' 참조하지 않거나, Compiler에서 프로그램이 variable에 의존하지 않는다 판단할 경우 자체적으로 최적화 시킬 수 있다. 이는 compiler의 구현에 따라 다르며 일반적으로는 해당되지 않음. <메인 메모리 구조> 코드 영역에는 일련의 명령어들이 텍스트 형태로 저장되어있다. 프로그램이 시작되고 종료될 때까지 M...

프로그램과 실행 3: 컴파일러 추가내용

  <컴파일러의 사용 효과> 컴파일러를 사용한 결과로 다음 조건들을 만족해야한다. 1. 변환 과정에서 프로그램의 뜻을 보존 2. 실용적인 면에서, 입력으로 들어온 프로그램을 어떤 면에서든지 개선. (어셈블리어를 기계어로 변환하는 경우 기계어가 해석할 수 있게 된다는 이점) (같은 언어로 옮긴 경우에는 성능이 개선되는 등의 이점이 존재해야함.) 위 두 가지를 만족하지 않는다면 굳이 컴파일러를 쓸 이유가 없다. <컴파일 과정> 컴파일러나 프로그래밍 언어의 특성에 따라 일부 단계는 생략되거나 더 세부적인 단계로 나뉠 수도 있다. 일반적인 과정은 다음과 같다. 구문 분석 소스 코드 파일을 읽어 개별 문법요소(연산자, 괄호, 식별자 등) 단위로 자른후, 이 문법요소들을 해석하여 추상 구문 트리 를 생성한다. 이 과정에서 문법에 맞지 않는 소스 코드는 사용자에게 알려준다. 최적화 추상 구문 트리 를 분석하여 최적화를 수행한다. 도달할 수 없는 코드를 식별하거나, 상수 표현식을 미리 계산해 두거나, 루프 풀기 등의 대부분의 최적화가 이 단계에서 수행된다. 코드 생성 최적화된 구문 트리로부터 목적 코드를 생성한다. 목표 언어가 기계어일 경우, 레지스터 할당 , 연산 순서 바꾸기 등 하드웨어에 맞는 최적화 가 이 단계에서 수행된다. 대부분의 하드웨어 최적화 알고리즘 은 NP 복잡도를 갖지만, 휴리스틱을 통해 많은 최적화가 수행된다. 링킹 목적 코드가 기계어일 경우, 여러 라이브러리 목적 코드를 묶어 하나의 실행 파일을 생성하게 된다. 이 과정은 링커에 의해 수행되며, 어떤 사람들은 링커를 컴파일러의 일부로 간주하지 않기도 한다. <일단 구조와 다단 구조> 일단 구조 원시 코드 -> READ -> 번역 -> 목적 코드 다단 구조 원시 코드 -> READ -> 번역 -> 중간 코드1 -> ... -> 목적 코드 다단 구조에서 중간코드의 효용 1. 다양한 언어 지원   다양한 입력 언어를...

프로그램과 실행 2 : JVM, JIT

이미지
<JVM> ( JAVA SE7 에디션에 기반 JVM 개요도 ) 이전 글 "프로그램과 실행1" 에서는  .java 파일 -> 컴파일 -> 바이트코드 .class 클래스 파일까지 다루었다. 위 그림을 참고하고 이어서 기계어까지의 번역 과정을 설명하면, JVM은 Class loader를 통해 생성된 바이트코드인 .class파일을 JVM 규격에 정의된 대로 로드한다. 그 후, 바이트코드를 기계어로 번역할 때  JIT 컴파일러 를 사용한다. <JIT> JIT는 Just In Time의 약자인데, JIT 컴파일이라고하면,   C나 C++에서 하는 것처럼 프로그램을 실행하기 전에 처음 한 번 컴파일하는 대신,  프로그램을 실행하는 시점 에서 필요한 부분을 즉석으로 컴파일 하는 방식을 말한다. JIT 컴파일러 는 같은 코드를 매번 해석하는 대신 처음 실행될 때 인터프리트를 하면서 자주 쓰이는 코드를 캐싱 한다. 이후에는 캐싱된 코드를 가져다 쓰기 때문에 인터프리터의 느린 실행 속도를 개선할 수 있다. 보다시피 Java는 컴파일언어지만, 기계어로 변환되기까지는 JVM에서 인터프리팅 과정을 추가적으로 거친다. <JVM의 특성> 스택 기반의 가상 머신 단일 상속 형태의 객체 지향 프로그래밍을 가상 머신 수준에서 구현 포인터를 지원하되 C와 같이 주소 값을 임의로 조작이 가능한 포인터 연산이 불가능 가비지 컬렉션 사용 모든 기본 타입의 정의를 명확히 함으로써 플랫폼 독립성 보장 데이터 흐름 분석(영어: data flow analysis)에 기반한 자바 바이트코드 검증기(영어: verifier)를 통해 스택 넘침, 명령어 피연산자의 타입 규칙 위반, 필드 접근 규칙 위반, 지역 변수의 초기화 전 사용 등 많은 문제를 실행 전에 검증한다.         -> 실행 시 안전을 보장하고 별도의 부담을 줄여줌 명령어에서 스택에서 가져올 피연산자의 타입을 ...

프로그램과 실행 1 : 실행, 프로그램, 프로세스, 컴파일

<실행> 컴퓨터 혹은 Virtual Machine이 컴퓨터 프로그램의 코드로 작성된 Logic을 수행하는 행위. <프로그램, 프로세스> 예를 들어, 'A 프로그램'은 하드디스크 등의 매체에 바이너리 형식의 파일로 저장되어 있다가 사용자가 실행시키면 메모리로 적재되어 실행된다. 이 과정은 OS가 관여한다. OS가 'A프로그램'을 실행시키면 'A프로그램'의 1개의 인스턴스가 생성되는데 이를 프로세스라고 부른다.  프로세스화(인스턴스화) 된 이후로는 CPU의 자원을 점유하면서 코드에 명세된 작업을 수행한다. 1개의 프로그램에서 여러개의 인스턴스가 생성될 수 있고, 이는 곧 여러개의 프로세스가 생성되는 것을 말하며 OS는 한 프로그램에서 생성된 여러개의 프로세스를 PID ( Process ID )로 관리한다. 프로세스는 OS가 관리하는 가장 기본적인 단위이다.  프로세스는 Process를 기준으로  프로그램 수행 및 스케줄링을 조정한다. <컴파일> 컴파일 특정언어를 다른 특정언어로 번역하는 과정이다. 어셈블리어는 기계어의 바로 상위단계 언어이다. 어셈블리어를 기계어로 번역하는 과정을 컴파일 기계어를 어셈블리어로 번역하는 과정을 역컴파일 과정이라고한다.  초기 컴퓨터 프로그램들은 어셈블리어로 작성되었다. 어셈블리어는 하드웨어가 인식할 수 있는 기계어로 바꾸어주어야  어셈블리어로 작성한 프로그램 로직을 수행할 수 있다. 모든 프로그램 언어가 마찬가지이다. 서로 다른 CPU 아키텍처가 등장할 때마다 매번 똑같은 프로그램을  서로 다른 어셈블리어로 작성하는 비용이 커지면서,  고급 프로그래밍 언어의 필요성이 대두되었다. 이를 테면 같은 계산기 프로그램을 판매하려면, Intel이 제조한 CPU AMD가 제조한 CPU  ARM이 제조한 CPU...등 갖가지 하드웨어 제조사의 명령어셋에 맞게 다시 작성해야했다. 프로그램 제조사 입장에서는 상당히 비용과 시간이 드는 작업이...

이 블로그의 인기 게시물

실무진 면접 경험으로 정리하는 백엔드 (1) : 에듀 테크 기업 면접

노마드코더 개발자북클럽 Clean code TIL 6 : 6장. 객체와 자료구조

백엔드 개발자가 Djnago fullstack 사이드 프로젝트를하며 ( html, css, vanillaJS 그리고 JS프레임워크 )