제프리 리처의 CLR via C#(저자, 제프리 리처)
COM → Component Object Model
: MS의 SW 컴포넌트 기술로 오브젝트 기반의 컴포넌트 아키텍처를 제공한다.
CLR → Common Language Runtime
1장 목표
.Net Framework 설계 내용 및 배경 기술 소개.
1개 이상의 클래스, 구조체, 등의 타입을 포함하는 소스 코드를
응용프로그램 또는 재배포 가능한 구성 요소로 만드는 과정을 소개.
소스 코드를 관리 모듈로 컴파일하기
CLR이란 무엇을 의미하는가?
공용 언어 런타임Common Language Runtime의 약자로, 다른 프로그래밍 언어들 사이에서 공동으로 사용할 수 있는 실행 환경Runtime을 말한다.
CLR은 어떠한 장점을 가지는가?
- CLR의 핵심 기능은 메모리 관리, 어셈블리 로딩, 보안, 예외 처리, 스레드 동기화, 등이 있는데 이러한 요소들을 CLR을 지원한다면 제약 없이 자유롭게 사용할 수 있다.
- 다음의 예시 사항들을 보자
- CLR을 지원하는 언어라면, 실행 시점에서 오류가 발생했을 시 예외 처리를 통하여 오류 발생 사실을 알 수 있다.
- CLR은 스레드 프로그래밍 기능을 제공하기 때문에 CLR을 지원하는 언어는 자유롭게 스레드를 만들 수 있다.
CLR의 가진 다른 이점들
CLR은 런타임에서 프로그래머가 어떠한 언어를 사용하여 개발했는지 알 수 없다. 단순히 소스 코드가 컴파일러를 통해서 CLR 환경에서 잘 작동할 수 있도록 한다면 한 언어에 종속되는 것이 아니라, 다양한 언어를 통해서 개발할 수 있다.
선택한 프로그래밍 언어를 다른 프로그래밍 언어와 사용할 수 있다는 것은 큰 이점이다. 예를 들어서 수학에 관련되거나 금융 목적의 프로그램을 만드는 경우, APL 문법을 섞어서 개발한다면 개발 시간을 단축할 수 있을 것이다.
APL (A Programming Language) ?
Kenneth E. Iverson 박사가 1960년대에 개발한 프로그래밍 언어로 다음과 같은 특징을 가진다.
- 배열 중심의 언어 : 다차원 배열, 행렬 연산에 최적화
- 간결한 표기법 : 복잡한 배열, 벡터 연산을 한 줄로 표현
수학, 과학 계산 및 알고리즘에 강점을 가진 언어이며 금융, 학계에서 사용된다. 2024년에 들어서는 범용적으로 사용되고 있지는 않다.
MS는 CLR과 호환되는 언어의 컴파일러를 다수 만들었는데, C++, C#, VB, F#, IL 어셈블러 등이 있다. 또, MS뿐만 아니라 다른 회사, 개인, 등의 인원들도 CLR을 지원하는 컴파일러들을 만들었다.
CLR의 컴파일 과정
C# 소스 코드 → C# 컴파일러 → 관리 모듈(IL, 메타데이터)
VB 소스 코드 → VB 컴파일러 → 관리 모듈(IL, 메타데이터)
IL 소스 코드 → IL 컴파일러 → 관리 모듈(IL, 메타데이터)
CLR을 지원하는 프로그래밍 언어라면 소스 코드 파일은 위와 같은 과정을 통해 컴파일 된다. 프로그래밍 언어로 제작한 소스 코드를 해당하는 컴파일러에서 문법 점검과 소스 코드 분석을 통해서최종적으로는 관리 모듈Managed Module을 결과물로 얻을 수 있다.
관리 모듈은 실행하기 위해서 CLR을 필요로 하는 32비트 윈도우용 표준 PE 파일(PE32) 또는 64비트 윈도우용 표준 PE 파일(PE32+)의 포맷을 가진다.
관리 어셈블리는 윈도우 환경에서 데이터 실행 방지Data Execution Prevention, DEP와 임의 기준 주소Address Space Layout Randomization, ASLR와 같은 기술의 이점을 누릴 수 있다
관리 어셈블리 (Managed Assembly) ?
관리 어셈블리는 관리 모듈들이 IL 코드, 메타 데이터와 함께 패키징된 PE 파일 형태를 말하는데 하나 이상의 관리 모듈로 이루어진, 배포 및 실행 단위다. 대표적으로 DLL 파일 포맷의 형태를 예시로 들 수 있다.
데이터 실행 방지 (Data Execution Prevention) ?
CPU에서 데이터 메모리 영역의 실행을 금지하여 코드 인젝션 공격을 막는다.
임의 기준 주소 (Address Space Layout Randomization) ?
프로세스마다 메모리 주소 배치를 랜덤하게 설정하여 공격자가 메모리 주소를 알아내기 어렵게 보안을 강화하는 기법이다.
관리 모듈 vs 관리 어셈블리
관리 모듈은 .NET 언어로 작성된 소스 코드 파일을 가리키는 개념이며, 관리 어셈블리는 관리 모듈들을 IL 코드, 메타데이터, 매니페스트와 함께 패키징한 실행 가능한 단위다.
관리 모듈의 각 영역
영역 명칭 | 설명 |
PE32(+) 헤더 | 표준 윈도우 PE 파일 헤더로, 해당 영역에 속한 값이 PE32일 경우, 32비트 윈도우와 64비트 윈도우에서 모두 실행이 가능하고 PE32+일 경우에는 64비트 윈도우에서만 실행이 가능하다. 해당 영역은 응용프로그램의 타입을 구분하기도 하는데, GUI, CUI, DLL의 존재 여부를 구분하며, 파일 생성 시간도 가지고 있다. IL 코드만을 포함하는 모듈의 경우에는 해당 영역이 무시된다. 네이티브 CPU 코드만을 포함하는 모듈의 경우에는 해당 영역에 네이티브 CPU 코드 정보가 포함된다. |
CLR 헤더 | 해당 영역에는 관리 모듈을 만들기 위한 정보가 포함된다. 필요한 CLR 버전의 정보, 일부 플래그, 관리 모듈의 진입점 메서드의 MethodDef 메타데이터 토큰, 모듈 내의 메타데이터, 리소스, Strong name(??), 기타 플래그, 등의 정보를 가지고 있다. |
메타데이터 | 관리 모듈에는 메타데이터 테이블을 가지고 있으며 다음과 같은 두 종류를 가진다. 1) 소스 코드에 정의된 타입들과 멤버들의 선언을 설명하는 테이블 2) 소스 코드에서 참조하는 타입들과 멤버들에 서술하는 테이블 |
IL Code | 소스 코드를 컴파일 하여 생성된 코드로, 실행 시 CLR은 IL 코드를 네이티브 CPU 명령어로 컴파일하게 된다. |
CLR 호환 컴파일러의 컴파일 과정
네이티브 코드 컴파일러는 특정 CPU 아키텍처(x86, x64, ARM 아키텍처)에 맞춘 코드를 생성한다. 이와 달리, CLR 호환 컴파일러는 IL 코드를 대신 생성한다. IL 코드는 CLR이 실행을 관리하기 때문에 종종 관리 코드Managed Code로도 불린다.
CLR을 지원하는 컴파일러는 IL 코드 생성 시, 관리 모듈에 대한 메타데이터를 작성한다. 위에 표에서 잠깐 정리한 것과 같이 메타데이터는 관리 모듈 내부의 타입과 구성 멤버 및 외부 참조 모듈 정보, 등과 같은 정보를 가진 테이블의 집합이다.
메타데이터는 IL 코드를 포함하는 파일과 항상 함께 하는데, 이는 메타데이터가 EXE/DLL 파일 안에 포함되어 있기 때문이다. 또, 컴파일러가 메타데이터와 코드를 동시에 생성하여 관리 모듈 안에 두기 때문이다.
이로 인해서 IL 코드와 메타데이터는 설명에 차이점이 발생하는 일은 일어나지 않는다.
위에서 알아본 것 처럼, MS의 IL 어셈블러는 IL 코드와 메타데이터(혹은 가비지 수집이 가능한 관리 데이터)를 생산한다.
최종적으로 소프트웨어를 사용하는 유저는 CLR을 설치해야 관리 코드 및 관리 데이터를 포함하는 모듈을 실행할 수 있다. Visual Basic을 사용하기 위해서 런타임 DLL을 설치했던 것과 동일한 원리다.
기본적으로 MS의 C++ 컴파일러는 빌드 시 관리 되지 않는 네이티브 코드를 EXE/DLL 모듈 안에 포함하고, 실행 시 관리되지 않는 데이터를 조작하는 EXE/DLL 모듈을 빌드 한다. 이렇게 만들어진 모듈은 실행 시에 CLR을 필요로 하지 않는다.
단, C++ 컴파일러에 /clr 명령을 지정하면, 관리 코드(IL)를 포함하는 모듈을 생산하며 실행을 위해서는 CLR이 필요하다.
관리 모듈들을 하나의 어셈블리로 통합하기
어셈블리Assembly ?
CLR은 모듈을 실제로 다루지 않고 어셈블리를 다룬다. 어셈블리는 추상적이라 이해하기가 어려울 수 있는데 설명 하자면, 하나 이상의 모듈이나 리소스 파일들에 대한 논리적인 그룹이면서 재사용, 보안, 버전 관리의 가장 작은 단위이다.
선택한 툴과 컴파일러에 따라서 단일/복수의 어셈블리를 얻을 수 있으며, CLR에서는 어셈블리를 컴포넌트Component라고 부른다.
어셈블리는 1개 이상의 관리 모듈과 1개 이상의 리소스 파일(또는 데이터)로 이루어져 있으며, 매니페스트Manifest라는 데이터 블록을 포함하며 PE32, PE32+ 형태의 포맷으로 생성된다.
매니페스트는 메타데이터 테이블의 집합을 의미하는데, 어셈블리를 구성하는 파일, 어셈블리 밖으로 공개된 타입들, 어셈블리와 연관된 리소스 혹은 데이터 파일에 대한 정보들로 이루어져있다.
컴파일러는 어셈블리를 만든다.
컴파일러는 복수의 관리 모듈을 하나의 어셈블리로 만드는 작업을 수행한다. C# 컴파일러의 경우에는 매니페스트를 포함하는 관리 모듈을 결과물로 가진다.
매니페스트는 어셈블리가 단일 파일로 이루어져있음을 나타낸다. 그렇기 때문에 관리 모듈이 하나이며, 리소스(또는 데이터) 파일이 없는 프로젝트의 경우에는 어셈블리가 관리 모듈이 될 수 있다.
이 경우에는 빌드 과정이 추가 과정 없이 끝난다.
어셈블리를 사용하는 이유가 무엇인가?
- 안전하고 재사용 가능하며 컴포넌트 버전 관리가 가능한 논리적 개념과 물리적 개념을 만들 수 있다.
- 사용 빈도가 적은 타입이나 리소스를 분리하여 어셈블리의 일부로 구성할 수 있다. 분리된 파일을 필요에 따라 다운로드 하여 디스크 공간을 절약하며 한 번에 큰 크기의 파일을 배포하지 않고 분리하여 나누어서 배포할 수 있다.
- 어셈블리의 모듈에는 참조된 어셈블리에 대한 정보(버전 정보를 포함)가 존재한다.
- 이러한 개념은 어셈블리를 자기 설명적Self-describing으로 만든다.
- 해당 개념을 통해서 CLR은 실행에 필요한 종속성 관계를 알아낼 수 있다. 추가 정보가 필요 없기 때문에 비관리 컴포넌트에 비해서 배포 절차가 간편하다.
공용 언어 런타임 로딩
컴퓨터에 .Net Framework 설치 여부 파악
%SystemRoot%\Microsoft.NET\Framework %SystemRoot%\Microsoft.NET\Framework64
CLR은 어셈블리 안의 코드를 실행하기 위해서 .Net Framework가 있어야 한다. 위 경로를 통해서 설치 여부를 파악할 수 있다.
C:\Program Files (x86)\Microsoft SDKs/Windows{Version}\bin
책에서는 .Net Framework SDK 폴더에서 clrver.exe 프로그램을 찾을 수 있다고 했으나 윈도우 11을 기준으로 위 경로에서 찾을 수 있었다. clrver.exe 프로그램을 통해 CLR의 버전을 확인할 수 있다.
아래의 옵션을 통해서 설명에 해당하는 기능들을 사용할 수 있다.
옵션 | 설명 |
-all | CLR을 사용 중인 컴퓨터에 모든 프로세스를 표시한다. |
pid | 지정한 프로세스 ID(PID)를 가진 프로세스에서 사용하는 CLR의 버전을 표시한다. |
-? | 도구의 명령 구문 및 옵션을 표시한다. |
32비트 윈도우 vs 64비트 윈도우
어셈블리가 타입 안정성을 준수하는 관리 코드type-safe managed code만을 포함하면 32비트, 64비트 윈도우에서 서로 작동되는 코드를 작성한 것이다.
컴파일러를 통해서 생성되는 EXE/DLL 파일은 32비트, 64비트 윈도우에서 정확하게 실행되도록 만들어진다.
간혹, 안전하지 않은 코드Unsafe Code를 사용하거나 특정 CPU 아키텍처를 대상으로 하는 코드가 존재하는데 이 경우, C# 컴파일러에서는 /platform 스위치를 통해서 설정할 수 있다. 해당 스위치를 사용하지 않을 경우 기본 값인 anycpu로 설정된다.
실행 파일을 실행 프로세스
실행 파일 실행 시 윈도우는 실행 파일 헤더를 통해서 32비트, 64비트 주소 공간Address Space 중에 결정할 수 있으며 CPU 아키텍처 정보(x64, x86)를 확인해 컴퓨터 CPU에서 실행이 가능한지 확인한다.
왜 32비트는 x32가 아니라 x86인가?
32비트 아키텍처를 x86로 지칭하는 이유는, 처음으로 32비트 아키텍처가 적용된 곳이 1970년대에 인텔에서 발표한 CPU, 인텔 8086이었으며, 당시에는 ‘8086 프로세서 아키텍처’라고 불렀기 때문에 시간이 지나면서 86이라는 숫자가 32비트 아키텍처를 지칭하는 용어가 되었기 때문
64비트 윈도우의 경우에는 WoW64(Windows on Windows 64) 기술을 통해서 32비트 윈도우 응용 프로그램을 실행할 수 있다.
Wow64 (Windows on Windows 64) ?
64비트 버전 윈도우에서 32비트 응용 프로그램과의 호환성을 해결해주는 기술이다. sysWoW64 폴더 안에 32비트 DLL과 시스템 파일이 존재한다.
EXE 파일 헤더 정보를 통해 32비트, 64비트 프로세스 중 생성되는 프로세스가 선택되었다면 MSCoree.dll을 메모리 공간으로 불러온다.
MSCoree.dll ?
.Net Framework의 구성 요소로, .Net 프로그램의 실행에 필요한 기능(CLR 호스팅, 어셈블리 로딩, 호스트 관리, CLR 버전 관리, 등)을 제공한다.
해당 DLL 파일을 통해서 프로세스의 주 스레드Primary Thread는 CLR을 초기화하며 EXE 어셈블리를 불러들이고 진입점Entry Point 메서드(Main 함수, 기타) 호출을 시도한다. 이 시점에서 관리 응용 프로그램이 실행된다.
만약, 관리되지 않는 어플리케이션에서 Win32의 LoadLibrary 함수를 통해서 관리 어셈블리를 로드한다면, 윈도우에서는 알아차리고 CLR이 실행되지 않은 경우, CLR을 로드하고 어셈블리에 포함된 코드를 처리한다.
코드 작성 시, Environment 클래스의 Is64BitOperatingSystem 프로퍼티를 사용하여 지금 실행되는 환경이 64비트 윈도우인지 식별할 수 있다.
같은 클래스의 Is64BitProcess 프로퍼티는 현재 프로세스가 64비트 프로세스인지 값을 알 수 있다.
어셈블리 코드 실행하기
IL ?
IL은 MS가 여러 외부 상용 및 학술용 언어/컴파일러 제작자와 협의하여 만든 CPU의 독립적인 기계어 코드로 다른 대다수의 CPU 기계어보다 더욱 높은 수준의 언어다.
객체 타입에 접근하고 조작할 수 있고 객체를 생성하거나 초기화 할 수 있으며 가상 메서드를 호출하고 배열 요소를 직접 조작할 수 있는 명령어들을 가지고 있다. 뿐만 아니라 예외 처리를 위한 Throw와 Catch 명령어도 가지고 있으므로, IL을 객체 지향 기계 언어로 볼 수 있다.
IL은 어셈블리어로도 사용이 가능한데, 이를 위해 MS는 ILASM.EXE라는 어셈블러와 ILDASM.EXE라는 역어셈블러를 제공한다.
IL의 메서드 실행
메서드 실행을 위해서 IL 코드는 JIT(Just-In-Time) 컴파일러를 통해 네이티브 CPU 명령어로 변환하게 되는데 아래의 예시를 통해서 그 과정을 살펴보자.
- 예제 코드
static void Main() {
1. Console.WriteLine("Hello");
2. Console.WriteLine("GoodBye");
}
- 프로세스 (1번째 줄)
- Main 메서드 실행 전, CLR은 Main 메서드에서 참조된 모든 타입을 알아낸다.
- 해당 과정에서 내부 자료 구조를 하나 할당한다. 이후, 참조된 타입에 대한 접근 관리 용도로 사용하게 됨
- 예제 코드에는 Console 클래스만 사용되어 해당 클래스에 대한 메서드들을 해당 내부 자료 구조에 저장한다.
- 내부 자료 구조에는 메서드를 실행할 수 있는 코드의 메모리 주소 값들을 보관하게 된다.
- JIT에서 Console 클래스 어셈블리 메타데이터에서 WriteLine 메서드를 찾고 해당하는 IL을 가져온다.
- 메모리 블록을 할당한다.
- IL을 네이티브 CPU 명령어로 변환, 이전 단계에서 할당된 메모리 블록에 결과물을 저장한다.
- 타입 테이블 내의 메서드 항목 주소를 3번째에서 할당한 메모리 블록을 가르키게 변경한다.
- 이후, 메모리 블록으로 이동하여 코드를 실행한다.
- Main 메서드 실행 전, CLR은 Main 메서드에서 참조된 모든 타입을 알아낸다.
위 프로세스를 통해서 1번째 줄의 코드는 컴파일이 완료되었다. 이후 2번째 줄의 코드는 다음과 같은 프로세스를 가진다.
- 프로세스 (2번째 줄)
- 1번째 줄에서 Console 클래스의 WriteLine 메서드에 대한 데이터를 확보했다.
- 확보한 메서드는 String을 매개변수로 받는 WrtieLine 메서드다.
- 이전과 달리, JIT 컴파일러를 거치지 않고 메모리 블록으로 이동하여 코드를 실행한다.
- 1번째 줄에서 Console 클래스의 WriteLine 메서드에 대한 데이터를 확보했다.
1번째 줄과 2번째 줄 코드의 프로세스를 보면서, 성능 저하Performance Hit는 메서드를 최초 실행할 때 1회 발생한다는 것을 알 수 있었다. 네이티브 CPU 명령어가 동적 메모리 상에 존재하기 때문에 다시 최초와 같은 프로세스를 실행할 필요가 없다.
할당된 메모리 블록은 응용 프로그램의 종료와 함께 소거한다. 재실행, 혹은 동시에 2개 이상의 인스턴스를 실행하는 경우 IL 코드를 네이티브 CPU 명령어로 읽어오는 작업이 재진행된다.
왜 인스턴스는 네이티브 CPU 명령어를 공유하지 않는가?
인스턴스는 독립적으로 돌아갈 수 있도록 보장되어 있다. 이는 프로그래머의 의도 없이 서로 인스턴스 영역을 침범하게 된다면 프로그램이 정상적으로 작동하지 않을 확률이 있기 때문이다.
컴파일러 코드 최적화
컴파일러가 최적화된 코드를 만드는 것은 실행 속도에 빠르다는 이점이 있으나, 만드는 과정이 최적화를 적용하지 않는 것 보다 많은 시간이 걸린다.
장점과 단점이 존재하기 때문에 C# 컴파일러는 프로그래머에게 최적화 여부를 설정할 수 있는 스위치를 제공하고 있다.
스위치 설정 | C# IL 코드 품질 | JIT 네이티브 코드 품질 |
/optimize- /debug- (Default) | 최적화 X | 최적화 O |
/optimize- /debug(+/full/pdbonly) | 최적화 X | 최적화 X |
/optimize+ /debug(-/+/full/pdbonly) | 최적화 O | 최적화 O |
/optimize- 스위치를 사용하면 최적화 미적용의 IL 코드가 생성된다. 다수의 NOP(No-Operation) 명령어와 다음 줄로 이동하기 위한 브랜치Branch 명령어가 포함되어 있다.
포함된 명령어들은 Visual Studio에서 디버깅 중 제공하는 편의 기능을 만들기 위해 만들어진다.
최적화된 IL 코드를 생성하면, 불필요한 NOP 명령어와 브랜치 명령어를 제거한다. 또, 디버거가 흐름 제어를 한 단계씩 추적하기 어렵게 만들게 된다. 일부 함수 평가식Function Evaluation들은 디버거 안에서 미작동하게 된다.
이로 인해서 IL 코드는 더 작아지고 좀 더 읽기 쉬운 방법으로 변환된다. 생성한 EXE/DLL 파일의 용량도 적어진다.
IL의 특성
IL은 스택 기반의 언어로, IL 명령어들과 피연산자Operand들은 실행 스택 위에 쌓이고(Push) 스택을 통해서 꺼내는(Pop) 방식으로 실행된다. 또, IL은 레지스터 명령어를 제공하는 것이 아니다.
IL 명령어는 타입 종류에 무관하다. 예시를 들자면, IL은 스택에 들어온 두 개의 피연산자를 더하는 명령어를 제공한다. 이때, 32비트와 64비트 버전 사이에 별다른 구분이 없다.
여태 서술해온 IL은 CPU 내부로부터 추상화된 동작들에 강하다는 것을 알 수 있었다. 하지만, 가장 큰 장점은 추상화된 동작이 아니라, 응용 프로그램의 견고함과 보안성에 있다.
IL을 CPU 명령어로 만들면서 CLR은 확인Verification 과정을 거치는데, 이를 통해 높은 수준의 IL 코드를 검사하고 코드가 수행하는 작업이 안전한지 검증한다. 검증을 통해, 모든 메서드가 정확한 수의 매개변수로 호출되는지, 모든 메서드에 전달된 각 매개변수의 파라미터가 올바르게 사용되는지, 반환문이 있는지, 등을 확인한다.
이러한 정보들은 관리 모듈의 메타데이터를 통해서 가져온다.
윈도우의 가상 주소 공간Virtual Address Space
윈도우에는 가상 주소 공간이 존재한다. 이는 응용 프로그램의 코드를 신뢰할 수 없기 때문인데, 응용 프로그램이 올바르지 않은 접근이나 잘못된 주소를 참조하려고 할 때가 흔한 일이었기 때문이다.
가상 주소 공간을 통해서 윈도우 프로세스들을 서로 분리된 공간에 배치하여 견고함과 안정성을 얻을 수 있으며, 프로세스가 다른 프로세스에 침범하는 것을 방지할 수 있다.
앞서 서술한 확인 과정을 통해서 검증된 코드들은 부적절한 메모리 액세스가 없으며, 다른 응용 프로그램에 영향을 미치지 않는 다는 것을 확인되었기 때문에 윈도우에서 여러 개의 관리 응용 프로그램을 실행할 수 있다.
개인 추천) 프로세스의 설계 부분도 굉장히 흥미로운 부분이다. 이 부분에 대해서 지식을 보충하고 싶다면 ‘뇌를 자극하는 윈도우즈 시스템 프로그래밍(저, 윤성우)’ 서적을 굉장히 추천한다. 대중적이며, 동영상 강의도 있으면서 설명이 굉장히 친절하다.
안전하지 않은 코드Unsafe Code
MS의 C# 컴파일러는 기본적으로 안전한 코드를 만들어낸다. 하지만, 설정을 통해서 안전하지 않은 코드를 생성할 수 있는데, 안전하지 않다는 것은 다음을 의미한다.
- 직접 메모리 주소를 제어할 수 있다.
- 원하는 메모리 주소에 데이터를 추가할 수 있다. 실행 속도에 민감한time-critical 알고리즘의 성능을 향상하려고 한다면 매우 유용하다.
- 데이터 구조를 훼손할 가능성이 존재한다.
- 시스템을 공격하거나 보안 취약점을 만드는 데에 이용될 수 있다.
사유들이 꽤 크리티컬하기 때문에 C# 컴파일러는 안전하지 않은 코드를 포함하는 메서드는 반드시 unsafe 키워드를 붙이게끔 강제하고 있다.
JIT 컴파일러가 안전하지 않은 메서드를 컴파일 시도를 할 경우, ‘System.Security.Permissions.SecurityPermissionFlag’의 Bool형 변수 ‘SkipVerification’ 값을 ‘System.Security.Permissions.SecurityPermission’ 특성이 가지고 있는지 확인한다.
값이 참인 경우, JIT 컴파일러는 컴파일하고 실행하며, CLR은 이 코드를 신뢰하게 된다. 만약에 값이 거짓인 경우, JIT 컴파일러는 System.InvalidProgramException 예외 혹은 System.Security.VerificationException 예외를 발생시켜서 실행을 방지한다.
CAS(Code Access Security)는 응용 프로그램 코드가 특정 권한을 가지고 접근하도록 제어하는 보안 기법이다. 하지만, 최신 버전의 .NET에서 지원하지 않는다. 만약, CAS 관련 API를 사용할 경우 오류가 발생할 것이다.
위에서 설명한 내용도 CAS에 속하는 내용이기 때문에 지금(2024년)은 사용되지 않는다.
'독서 > CLR via C#' 카테고리의 다른 글
[CLR/C#] 공유 어셈블리와 강력한 이름의 어셈블리 (0) | 2024.04.15 |
---|---|
[CLR/C#] 빌드, 패키징, 배포, 응용프로그램과 타입의 관리 (0) | 2024.04.15 |
[C#] IL 코드 확인 및 메타데이터 확인하기 (0) | 2024.04.15 |
[CLR/C#] CLR의 실행 모델 (2) (0) | 2024.02.11 |
[CLR/C#] 공부를 시작하면서... (0) | 2024.02.10 |