본문 바로가기
프로그래밍 언어/C 언어

C언어 1장<어셈블리어와 C언어>

by Suff07 2024. 1. 14.

0. C언어와 어셈블리어

먼저 C언어를 이야기하기전에 어셈블리어를 이야기하는편이 좋을것 같습니다.

 

먼저, 어셈블리어는 Low Level Language입니다.

여기서 말하는 저수준 언어란 유치하다라는 의미가 아니라 기계언어에 보다 가깝다는 의미입니다.
컴퓨터 쪽에서 이야기하는 저수준 언어는 기계어에 가깝다는 의미로 해석하시면 되고 반대로 High Level은 인간이 해석하기 좋은 언어라 이해하면 됩니다.

 

 

중요한건, 어셈블리어의 특징이 저수준 언어라 했으니 CPU에 종속이 됩니다.

이게 무슨말이냐면, CPU의 설계구조에 따라서 어셈블리어가 다르다 이겁니다.

 

그러니까 쉽게 따지면 PC CPU 제조사는 인텔과 AMD로 양분이 되잖아요?

 

이 두가지 CPU의 설계구조가 각각 다르기에 어셈블리어도 두가지로 갈라진다 이겁니다.

(사실, 더 정확하게 이야기하면 x86,amd64,Arm코어로 나뉩니다만 편의상 여기선 제조사로 구분합니다.)

 

즉, 내가 Intel CPU에서 어셈블리어로 코딩을 했다면 이것을 AMD CPU에서 실행시키는건 불가능하다라 이거죠!

 

어셈블리어의 예시를 한번 보고 넘어가도록 하겠습니다.

 

 push        ebp  
 mov         ebp,esp  
 sub         esp,0E4h  
 push        ebx  
 push        esi  
 push        edi  
 lea         edi,[ebp+FFFFFF1Ch]  
 mov         ecx,39h  
 mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]  
 mov         ecx,9AC003h  
 call        009A1316  
 mov         dword ptr [ebp-8],1  
 mov         dword ptr [ebp-14h],2  
 mov         eax,dword ptr [ebp-8]  
 add         eax,dword ptr [ebp-14h]  
 mov         dword ptr [ebp-20h],eax  
 mov         eax,dword ptr [ebp-20h]  
 push        eax  
 push        9A7D08h  
 call        009A10CD  
 add         esp,8  
 xor         eax,eax  
 pop         edi  
 pop         esi  
 pop         ebx  
 add         esp,0E4h  
 cmp         ebp,esp  
 call        009A123F  
 mov         esp,ebp  
 pop         ebp  
 ret

 

이게 어셈블리어 코드입니다. 이를 C언어로 번역하면 다음과 같습니다.

 

#include<stdio.h>

int main() {
    int a = 1;
    int b = 2;	
    int c = a + b;
    
    printf("%d", c);
}

 

 

더 자세한 설명을 원한다면 아래의 링크에서 참조하시면 좋을것 같습니다.

https://coding-factory.tistory.com/651

 

[Assembly] 어셈블리어 기초 사용법 & 예제 총정리

어셈블리어란? 어셈블리어(assembly language)는 기계어와 일대일 대응이 되는 컴퓨터 프로그래밍의 저급 언어입니다. 전류가 흐른다 그렇지 않다로 구성되는 0과 1의 이진수로 프로그램을 하는 기계

coding-factory.tistory.com

 


1. C언어의 등장

위의 코드를 보니 왜 C언어가 등장해야 할지 이해가 되시죠?

 

중요한건 위에서 언급한 어셈블리어는 Intel용 어셈블리어라는겁니다.

즉, AMD CPU에서 해당 코드를 실행시키려면 또 다시 AMD CPU의 어셈블리어를 알아야 한다는 점이 문제점이라 이겁니다!

 

저 복잡한걸 또 하라는게 얼마나 짜증나고 무시무시합니까!

 

그래서 C언어가 등장을 하게 되었습니다.(With Compiler)

여기서 컴파일러라는 아주 중요한 개념이 등장하는데 아래 그림을 보면서 설명을 해보겠습니다.

 

  • 소스코드는 우리가 흔히 말하는 소스코드 맞습니다.
  • 컴파일러의 역할은 크게 두가지가 있습니다.  1. 문법적 오류를 검사 2. 소스코드를 어셈블리 코드로 변환
  • 어셈블러는 어셈블리 코드를 바이너리 코드(2진법)로 변환, 바이너리 코드의 덩어리를 오브젝트 코드라 합니다.
  • 링커는 어셈블러가 만든 오브젝트 코드를 운영체제에 맞게 실행포맷을 구성시켜줍니다.

 

그러면 이제 궁금한게 두가지가 생길겁니다.

 

1. 어셈블리 코드는 CPU의 아키텍쳐에 따라 다르다고 했잖아요? 그러면 제가 MacBook에서 코딩을 하면 인텔 CPU가 장착된 PC에서는 그게 실행이 안되는게 맞는거 아닙니까?


 일단 답변을 해주자면 그러니까 컴파일러가 여러개가 존재합니다.

즉 Intel CPU에 맞는 컴파일러가 있고 ARM코어에 맞는 컴파일러가 C언어의 내부에 각각 존재하므로 문제없이 작동이 된다 이거죠~

 

 2. 그러면 바이너리 코드에서 링커가 하는 역할을 좀 더 설명해주세요

 

 

바이너리 코드는 2진 코드를 나열한것입니다. 이게 그러면 어떻게 실행이 되느냐?

 

운영체제에서 Linux의 실행파일인 .sh파일이 Windows에서 실행이 되는걸 본적이 있나요?

 

안됩니다! 안되요!

 

왜 그러냐면 윈도우와 리눅스의 실행파일 구성이 조금 다르기 때문입니다.

이는 돌려말하면, 실행파일은 운영체제에 종속적이다라는 말이 됩니다.

이를 위해서 링커라는 개념이 존재하며 윈도우면 윈도우답게 리눅스면 리눅스답게 실행포맷에 맞게 재포장 시켜주는 역할이 바로 링커가 하는 역할입니다.

'프로그래밍 언어 > C 언어' 카테고리의 다른 글

C언어 3장 <변수와 자료형1>  (1) 2024.10.13
C언어 2장 <Hello World~!>  (0) 2024.08.24
프롤로그  (0) 2024.01.14