본문 바로가기

Software/Embedded Linux

(중급) Embedded Linux System - 1일차

(중급) Embedded Linux System - 1일차


개발 환경설정



NEXUS Series 개발장비는 Embedded Linux System에서 공부를 하기에 최적의 교구제이다.

벤더 입장에서 여러가지 테스트를해 볼 수 있으며, 해당 디바이스에 대하여 최신 버전까지도 지원해 주고 있다.

또한 중고 가격이 저렴하기 때문에 장비 구매에 있어서 부담이 적다.


* 라즈베리파이 또한 개발 장비로 훌륭하다.


안드로이드에서 사용되는 C/C++ 라이브러리는 리눅스기반의 C 프로그램이므로, 윈도우에서 C/C++ 라이브러리를 만들려면 리눅스 버추얼 머신이 필요하다.

VMWare 나 Virtual-Box 같은 프로그램을 사용하여 리눅스를 설치하고, 해당 리눅스 환경에서 Android NDK를 설치하여 프로그램을 개발하는 방향으로 수업을 진행한다.


* Android NDK에 대한 설명은 하기 참조



VirtualBox -> Unbuntu 환경에서 실습.

네트워크 설정 필요

- 어뎁터2 ->네트워크 어뎁터 사용하기 Check->호스트 전용 어댑터 선택



Putty

- Window - Translation : ->UTF-8

- Session



Filezilla 프로그램 사용



Android NDK를 사용함

Bionic C 라이브러리를 사용하기 위해.

NDK는 새로운 안드로이드 버전이 나올때 마다 신버전이 나옴.(최신화 필요)


android-ndk-r13-linux-x86_64.zip root 폴더로 이동후 unzip 명령을 통해 압축해제.

#unzip android-ndk-r13-linux-x86_64.zip


Java Complier & LLVM Complier 비교


Java, C#

===▽===              :      compile

I.L : Intermediate Language(ByteCode)

===△===

Java(Dalvik), CLR



Java code 혹은 .NET이 제공하는 Language 들이 compile 되면 IL(Intermediate Language - Bytecode)이라는

중간 언어로 작성된 파일을  만들어 낸다.

그리고 Application이 실행 될 때, Java(Dalvik), Common Language Runtime(CLR) 이 

해당 IL 언어를 읽어들여 JIT(Just In Time) 컴파일을 하여 네이티브 코드로 만들어 실행을 한다.


그렇다면 왜 바로 처음부터 Native 코드를 만들지 않고, IL생성 이 후 Dalvik or CLR을 통한 2번의 Complie 과정을 거치게 되는 것일까?

 : 지원되는 여러가지 언어들이 모두 Platform에 최적화된 코드가 되게 하기 위함이다. 물론 컴파일 비용이 좀 부담스럽기는 하나, Target 기계에 최적화 되어 최고의 성능을 낼 수 있다.


CLR : .NET Framework가 지원하는 Common Language(C, C++, C#, Visual Basic 등)이 돌아가는 가상머신이다.


LLVM Compiler(C/C#) : 정적분석 용이함 -> Error Message 가 훌륭하다.

===▽===

I.L

===△▽===

기계어


LLVM Complier는 Apple이 지원하며, 최근 Google Chromium 에서도 지원하기 시작했다.

과거 구글이 LLVM이 느리다는 이유로 배척했었으나, 현재는 LLVM의 뛰어난 성능을 인지하고 많이 사용하기 시작함.

LLVM은 최근 가장 핫한 컴파일러다.

"정적분석이 용이하다 : 에러메시자가 훌륭하다"

또한 GNU 기반 컴파일러(GCC)와 동일한 기능 명령을 수행하기 때문에 GCC를 사용할줄 안다면, 사용하는데 문제가 되지 않는다.






Android NDK란?

안드로이드 NDK는 개발자가 Android application을 개발시 C코드로 개발할 수 있게 도와주는 Development Kit 이다.

: 안드로이드 애플리케이션에서 native code의 구성요소들을 포함할 수 있는 도구 모음을 말함.

: NDK는 다음의 기능을 제공한다.

- 개발 툴과 C, C++ 소스로 부터 native code 라이브러리를 만들 build file을 제공

- native library를 application packages file (.apks)에 함께 묶을 수 있는 방법을 제공

- native system의 헤더/라이브러리를 제공

: 제공 라이브러리

- libc, the standard C library

- limb, the standard math library

- JNI interface

- libz, the common Lib compression library

- liblog, android logging


JNI란?

: 자바가 다른 언어로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스를 제공한다.

: 자바가상머신(JVM)이 원시 메소드(native method)를 적재(locate)하고 수행(invoke)할 수 있도록 한다.

: JNI가 자바가상머신내에 포함됨으로써, 자바가상머신이 호스트 운영체제상의 입출력, 그래픽스, 네트워킹, 그리고 스레드와 같은 기능들을 작동하기 위한 로컬시스템호출(local system calls)을 수행할 수 있도록 한다.



Linux Directory


/root

1. android 

: android framework full source

du - h -s ./android 용량 확인하는 리눅스 명령어

- 안드로이드 framework의 용량은 약 53기가가 넘는다. 따라서 실제 안드로이드 빌드시 빌드컴퓨터를 따로 두는것이 좋다.

ex) 노트북으로 빌드시 약 20시간 걸렸음.


2. android-ndk-r13

:C/C++  Library


3.tegra

:arch/arm64 Tegra 칩을 사용하며 테그라는 칩이름이다.

테그라 폴더는 Linux Kernel source가 존재.


#make kernelversion  : 사용중인 커널 버전 확인 명령어(tegra 폴더 접근에서 사용)

: kernel.org 리눅스 최신 커널 다운로드 가능 사이트 

: 바닐러커널(실제 커널 소스가 아무런 수정이 이루어 지지 않는 커널 : 리누스 토발즈가 운영)

longterm:3.10.103

http://s.android.com/ 안드로이드 리눅스 커널 개발 사이트

-> Building Kernels

넥서스 디바이스가 사용중인 커널은 하기와 같다.

volantisdevice/htc/flounder-kernelkernel/tegraflounder_defconfig


크로스 컴파일러 환경변수 등록

echo $ARCH

echo $CROSS_COMPILE


 export ARCH=arm64

 exprot CORSS_COMPILE=aarch64-linux-android-




/tegra/arch 접근하면 리눅스 컴파일러가 지원하는 아키텍처 목록이 보인다.


우리가 사용하는 architecture는 arm64 이다.(확인 바람)

: arm - 32bit

: arm64 - 64bit


x86 - Intel/AMD 계열 32bit

ia64 - Intel/AMD 계열 64bit

기존에는 ia64가 아닌 amd64였다. 그 이유는 Intel 계열 64bit 칩은 AMD가 먼저 개발 했었기 때문이다. 하지만 지금은 intel , AMD 모두 서로의 장점을 추구하며 함께 발전하고 있다. 따라서 ia로 표기한다.


임베디드 시스템은 arm 으로 대동단결 한다. 하지만 ARM 도 문제점은 있었다.

리누스 토발즈가 arm에 대한 문제점 지적했었으며, 특히 포팅할때 문제가 발생함.

일반적으로 cpu가 바뀐다 하더라도 문제가 발생하면 안되는데, 발생됨.




aarch64-linux-android- Tab 입력을 해보면 현재 사용 가능한 ToolChain 목록 확인 가능하다.


환경 변수 설정.

~/.bashrc => bash shell 설정 (일반적으로 bash shall을 많이 사용하기는 하지만)

rc는 bash의 설정 저장 용도로 사용하는 것을 의미하며, 일반적인 사용자 변수를 저장하는 용도로 사용하진 않는다.

~/.bash_profile => bash shell이 시작될 때 수행된다.

~/.profile => root라는 계정에 종속된다.

/etc/profile => 모든 계정이 시작될 때 수행된다. (root 권한이 있어야만 수정 가능)


우리는 /etc/profile에 등록하도록 한다.


임베디드 리눅스에서 가장 중요한 것은 환경변수에 대한 세팅 부분이다.

드라이버를 만들다 보면 시스템 해당 부분에 대하여 중요함을 느끼게 된다.



코드 분석하기


일반적으로 vi -t task_struct를 쳐보면 task_struct에 대하여 분석 가능하다.

리눅스에서 코드를 분석할 때는 ctags를 이용한다.

ctags를 사용하기 위해서는 tags 파일을 생성해야 한다. 명령어는 다음과 같다.

$ctags -R


하지만!

=>커널에서는 위의 방법을 사용하지 않는다.

이유는 실제 리눅스에서는 무수히 많은 매크로를 사용하고 있기 때문에 분석이 힘들다. 따라서..


=>커널은 Makefile 'tags'를 생성하는 규칙을 제공하고 있다.


vim 설정 파일

~/.vimrc

~/.exrc

둘다 만들경우 하나가 적용안됨. 아마도 exrc..

우리는 vimrc를 사용한다.(vi ~/.vimrc)


vi

: tj(tag jump) task_struct

실제 해당하는 심볼(task_struct)로 이동하는 명령어


원래의 위치로 돌아가고 싶을때 쓰는 명령어

CTRL + T : 복귀

CTRL + ]  : 이동

G + ]  : 이동 리스트 포함 볼 수 있다.(이해가 잘 안됨.)



커널 빌드하기


타겟 디바이스에 커널를 빌드하기 위해 우리는 ADB를 사용한다.


ADB란 무엇인가?

ADB(Android Debug Bridge)는 Unix shell을 제공한다. 사용자는 emulator나 Android 연결장비에 다양한 명령어를 보낼 수 있다.


해당 디바이스에 맞는 설정이 필요.

- make flounder_defconfig

- make



이미지 복사

cp/arm64/boot/Image-gz-dtb ~/android/device/htc/flounder-kernel/

cd ~/android : ~/android 폴더로 이동

make bootimage : 명령어 실행.



안드로이드 장비(NEXUS 7) 연결 

Virtual box 실행창 하단 USB 부분 디바이스 선택


adb devices : 현재 연결된 디바이스 목록 출력

adb reboot bootlaoder : 연결된 장비가 부트로더 모드로 reboot됨



adb devices : 입력시 연결된 장비가 안보임

fastboot devices : fastboot ...

안드로이드 장비(NEXUS 7) 다시 연결 

Virtual box 실행창 하단 USB 부분 디바이스 선택



fastboot devices : 다시 입력

연결된 것을 확인 할 수 있다.


■ Fastboot이란?

ADB의 기능 중 한 부분으로, 주로 Android 기반의 Smart Device의 Flash Memory File System의 내용을 수정하는데에 사용된다.

Flash Memory의 각 Partition 부분에 따라 Flash, Erase, Reboot 등의 기능을 수행할 수 있다.

Fastboot는 Windows와 Linux 등에서 모두 사용 가능하며

(단, 해당 운영체제의 전용 ADT( Android Development Tool ) 사용 )

반드시 ADB( Android Debug Bridge ) USB Driver가 설치가 되어있어야 한다.


fastboot -w flashall : 명령어 입력

해당 명령어를 통해 커널이미지가 올라가야(교체) 정상이나, 안올라가는 경우도 발생.(원인 불명)



NDK를 이용한 빌드 방법 - (안드로이드 네이티브 컴파일 과정)


vi myapp.c 프로그램 작성

gcc myapp.c -o myapp

file myapp : executable 확인

adb push myapp /data : adb 명령을 통해 target device로 옮김

adb shell : 명령을 통해 접속 시도


실제 장비는 arm64기반임으로 크로스 컴파일리러를 통해 빌드를 다시해줘야 한다.


우리가 크로스 컴파일러를 바로 사용할 수 없는 이유

안드로이드는 "glibc"(GPL 기반)를 사용하지 않고 bionic c library를 사용하므로 모든 라이브러리와 헤더 파일의 위치가 다르다. 라이센스적인 이슈를 해결하기 위해서 "bionic C"를 사용한다.


크로스 컴파일러인 ndk-build를 이용하여 build를 하기위해 환경 변수를 설정한다.

 ndk-build tool은 /root/android-ndk-r13에 존재한다. : 해당 경로를 PATH 등록.


export PATH=$PATH:$PWD : 현재 경로 PATH 등록 


$PATH를 안쓰게 되면 현재 PATH에 대한 경로가 깨져버리게 되며 리눅스 기본 명령이 입력이 안되어 진다. 기존 PATH에 적용되도록 해당 명령을 반드시 기입해주기 바란다.


/etc/profile에도 등록을 해준다.

export PATH=$PATH:/root/android-ndk-r13


Android.mk 파일 생성

빌드전 Android.mk 파일을 jni 폴더로 옮겨야 한다. build tool은 jni(java native interface) 폴더에서

빌드되어 지게끔 구성되어 있다.


PIE 옵션에 대하여 인지 필요. 실행하려고 하는 실행파일에 대하여 PIE 옵션을 할당하여 64bit에서 32bit로 돌리기 위해 해당 옵션이 필요하다.

과거에는 보안 용도로만 사용했었음.


-->>>크로스 컴파일 시작

ndk-build myapp.c -o myapp


../libs/arm 폴더에 빌드된 파일이 존재확인


arm64로 크로스컴파일이 잘되었는지 확인해보자.

adb push myapp /data

adb shell

cd  data

./myapp : 해당 app 실행되는지 확인.


추가적으로 arm이라는 이름으로 생성된 모든 디렉토리의 myapp 실행파일이 넥서스 장비에서 정상 동작 하는것을 확인할 수 있었다.



이론에 대한 기본적인 개요


Linux                        :  Windows

System Call Interface  <-> Win32 API

하드웨어에서 제공하는 자원들을 OS에서 어떻게 지원해 주는지에 대하여 학습하며,

Kernel에서는 해당 자원을 어떻게 관리하는지 학습하고,

간단한 Device Driver를 제작해 봄으로써 File System Management간 어떻게 동작이 이루어지는에 대해 이해해 본다.


◆ 리눅스 운영 체제 구조

 






◆ 리눅스의 역사 및 특징


  •  Before UNIX
    - Multics : 1965 AT&T(Bell Lab), General Electronics, MIT
  • Epoch
    • 1969, Ken Thompson, "Space Travel" on PDP-7

            "Space Travel" 게임을 만들면서 계속적으로 기계어가 달라지는 문제 발생. 따라서 C Lang 작성.

    • Dennis Ritche
  • BSD
    • Bill Joy, Chuch Haley(대학원생)
    • ex, csh, paging based virtual memory system, TCP/IP, bfs, socket
    • 1993년 4.4BSD (final version, 이 후 BSDI 회사)
  • AT&T System V
    • Version 1, 2,.....7 System V etc... (System V는 상업적으로 시작되었다.)
    • region based virtual memory, IPC, remote file sharing, STREAM

IPC : Semaphore, msg Queue, PIPE...


Kernel을 만드는 두가지 방법 존재.

Micro-kernel 기반 OS와 Monolithic kernel 기반.


리눅스의 역사


Monolithic kernel 기반

- 다른 서비스를 이용하기 위해선 함수를 콜을 해야만 했다.

- 다른 서비스를 이용하려면 컴파일을 다시해야 했다.


Micro-kernel 기반

독립된 서비스가 메시징이라는 IPC의 개념으로 사용하여 동작한다.

마이크로는 다른 서비스 이용시 동적으로 이용가능하다.

* MacOS가 마이크로 방식을 취한다.


리누즈 토발즈는 monolithic 기반을 추구 했으며, 타넨바움 교수는 micro 기반을 추구하여 한때 논쟁을 버리곤 했었다.

둘중에 뭐가 좋은가?의 쟁점 및 질문은 지금에 와선 의미는 없다.

최근에 와서는 서로가 서로를 닮아가며 장점을 취하고 발전해 나아가고 있기 때문이다.



  • Commercial UNIX
    • XENIX(MS, SCO), SCO UNIX(SCO), AIX(IBM, Journaling FS), HP-UX(HP),
      ULTRIX(DEC, 최초의 MP), OSF/1 (Digital), .......
    • SunOS(Sun Microsystems, VFS, NFS), Solaris, Unixware(Novell)
  • Mach
    • 최초의 micro-kernel
    • chorus, Exo-kernel, SPIN, L4, .......
    • http://ssrnet.snu.ac.kr/~choijm/current_os.html
  • standard
    • SVID(System V Interface Definition), POSIX (IEEE), X/OPEN(Inc.)
    • UI(SUN, AT&T :  Solaris), OSF(OSF/1)
  • Linux
    • 리누즈 토발즈(헬싱키, linux 0.0.1, 타넨바움 교수님 : Minix[마이크로 커널기반 OS])
    • 리차드 스톨만 - FSF - Gnu is Not Unix(Linux, hurd, gcc, gdb, vim)
      -GPL License *a, *.so, HAL


리누즈 토발즈 : 시장의 모델

리차드 스톨만 : 성장의 모델

리눅스는 철저하게 성능 위주의 운영체제이다.


■ 리눅스의 특징 장점 

  • Open System - 무료다

  • Small is beautiful philosophy

- file: just stream of bytes : -> open(), read(), write()면 끝남.

  • Simpel and Coherent
- data, device, pipe, socket, memory, processs, .... can be treated as a single abstraction(file)
  • Portability(이식성)
- high-level language
- new paradigm : OO, client-server model, clustering, PDA, MM Server
  • True Parallelism
- Multitasking (Time Sharing), Multiprogramming, Multiprocessor, MPP

C언어라는 High-Level Language를 사용하기 때문에 이식성이 뛰어나다.

커널은 99%가 C언어 이며 나머지 1%가 하드웨어 쪽 설계를 위해 어셈블리로 되어 있다.

객체지향적 개발방향을 추구한다.(커널 소스를 보면 알 수 있다.)

서버 사이드 프로그래밍이 우수하다. 윈도우에서 Server개발을 하게 되는 경우 비용이 많이 들어간다.


■ 단점

  • Too many variant
- dumping ground
  • Not small and simple any more
- uncontrolled growth
  • Building-block approach(CUI)
- inappropriate for beginner
  • Lack of GUI
- not now


리눅스는 더이상 심플하지 않으며, 작지도 않다. 전세계 많은 사람들이 참여하는 프로젝트이고 따라서 파편화가 너무 많이 되어 있다. 때문에 초보자가 접근하기에는 진입장벽이 존재 한다.

또한 커널 소스를 이용하여 코드 작성시 코드를 공개해야 하고(금액적인 부분[GPL License] 고려),

CUI(Command User Interface) 자동성이나 생산성에선 용이하나, GUI(Graphic User Interface)부분이 취약 했으나 현재는 그렇지만은 않다.

 * GUI가 접근성이 용이하다.



Process Management


Process에 대한 기본적인 개념 정리


정의

실행하는 프로그램에 대한 인스턴스(객체)다.

프로그램 자체를 기본으로 process를 생성하여 로더가 메모리에 올린다.

(실행가능한 파일)            (실행중인 프로그램)

메모리에 존재하는가? 하드디스크에 존재하는가에 따른 기준.


리눅스에서는 process가 기본적인 스케쥴링의 단위로서 동작되어 진다.

실행 흐름과 주소공간에 따라 프로세스로 표현한다.

프로세스는 구조체로 이루어져 있다.(Task_struct) : Windows 경우 PEB(Process Environment Block)

PCB, PEB 정의 책 참조



프로세스 빌드 과정


 


1. gcc -E a.c -o a.o(전처리)

: 소스파일이 Pre Processor(전처리)작업이 수행됨.

- 소스파일의 주석 제거 및 Define을 치환 하는 작업을 수행하며, 각 선언된 헤더파일을 불러오는 역할을 수행한다. 

#include <stdio.h>에서 #의 의미는 전처리 과정에서 포함되어야 될 파일에 대한 수행을 묻는 구문이다.


2. gcc -S a.i -i a.s(컴파일)

: 컴파일 소스 파일을 '어셈블리어'로 번역 과정


3. gcc -c a.s -o a.o

: 어셈블리어를 기계어로 번역한다.


4. collect2 

: gcc는 collect2(linker) 프로그램을 통해 linking 과정을 거친다.

->ibc, libgcc, gegin.o end.o 필요한 파일.?


추가 정보 사항.

리눅스의 경우 결과 라인이 침묵인 경우 성공을 의미 한다. 따라서 그동안 해왔던 컴파일 과정의 경우 여러 일련의 과정이 생략되어 있었다. 생략된 방법을 확인하기 위한 방법은 하기와 같다.

1) gcc -v a.c : 모든 과정을 볼 수 있다.(verbose)

2) gcc a.c -save-temps : 도중에 발생한 모든 파일을 생성해준다.

(중간 과정에서 생성된 모든 파일을 삭제하지 않고 보존한다.)



Process 상태 전이


 


fork를 통해 process 생성한다.

ready to run의 상태 : 스케쥴링의 관리 대상으로 선정되었다는 의미.

(linux에서는 ready queue -> run queue라고 부른다.)



Kernel 프로그램이 아닌 User에 의해 만들어진 Process의 경우 User모드로 빠진다.

커널과 User process가 system call를 통해 왔다갔다 왔다갔다 하며 수행작업을 거친다.



sleep, lock 에 메모리를 많이 쓰게 되면 swap되어 suspended 상태로 빠지게 되며,

unlock이 되거나, 이벤트 호출이 이루어지면 복귀를 하게 되는데

바로 run 상태가 되는 것이 아니라 ready to run 상태로 진입하게 된다.



여담

* swap영역의 메모리 할당에 대하여

: 기존에 메모리가 작은 시절 2G~4G가 시절 1.5~2배 정도 할당 했었다.

: 지금은 32~64G를 주로 사용하는데, 크게 잡지 않는다. 기본 운영체제에서 권장하는 설정으로 메모리 스왑 영역을 설정하게 되면 32~64G 크기로 잡아 버리게 되며 문제가 발생하게 된다.

-> 따라서 swap 영역의 사이즈를 줄여 사용하는것을 권장한다.




Flow of execution : execution mode (cf: address space)

커널 모드와 유저모드간의 Process 전환에 대한 설명


리눅스에서는 kernel 모드에서 user 모드로 진출했을 때 반드시 호출되는 것이 스케쥴이다.

(ret_from_fork => schedule())


우선순위가 높은 프로세스가 존재한다면, 


(리눅스 커널 2.6부터 선점형 커널임.)

우선순위가 높은 프로세스에 의해서 제어권을 뺏기게 된다. 다음 그림을 통해 알아보자.


 


커널 모드에서 실행중


유저모드에서 프로세스 A실행 됨.


->fork()함수를 통해 자식 프로세스 생성.

:fork()는 시스템 함수이기 때문에 커널 모드로 진입하게 된다.

:interrupt가 발생되었으며, 커널 모드로 실행되어 짐.


현재 커널모드

fork()에 의한 자식 프로세스 B가 실행됨

->이때 ret_from_fork() =>스캐쥴러가 실행됨. (돌아갈 포지션에 대한 기록)



선점형 프로세스에 대한 이론 기준으로 설명.

당시 가장 우선순위가 높았던 프로세스 C가 실행됨.



커널 모드가 짧게 수행된것으로 보아 인터럽트가 발생된것을 확인함.

프로세스 B가 마저 수행되고,

다시 커널 모드로 진입하게 된다.



Context(System)


◆ System context : tast_struct에서 통합 관리함

task_struct 구조에 대한 설명 확인 가능(vi -t task_struct)

  • proc. Table

- identification  : pid, process group id, ...

- family relation

- state

- sleep channel : sleep queue

- scheduling information : p_cpu, p_pri, p_nice

- signal handling information

- address(memory) information

  •  U area

- stores hardware context when the process is not running currently

- UID, GID

- arguments, return values, and error status for system call

- signal catch function

- file descriptor

- usage statistics


커널에 대한 자료구조 이해가 필수 이다. 그 중 Linked List에 대한 사용법은 필수이다.

mm_struct(중요)

가상 메모리에 대한 맵핑 주소를 관리한다.

실제 메모리는 가상메모리에서 동작되어 지며, 이 주소가 물리주소에 맵핑되어 동작되어 진다.


리눅스에서 제일 처음 실행되는 start_kernel : (vi -t start_kernel)

stdin

stdout 

------------- : (line bufferd 정책)

stderr (non bufferd 정책)

flush에 대한 차이

실제 각각에 해당 하는 fd[](FILE*)가 다르다.


struct file*(fd_array[] 내부가 struct file*) 를 통해 공유되어 진다. 따라서

stdin 으로 "hello" 찍고 error로 "out"를 출력하면 "Hello world"라고 출력되는 이유


■ fork example

int glob = 6;

char buf[] = "a write to stdout\n"


int main(void)

{

int var;

pid_t pid;


var = 88;

write(STDOUT_FILENO, but, sizeof(buf)-1);

printf("before fork\n");


if((pid = fork()) == 0) { /* child */

glob++; var++;

} else {

sleep(2); /* parent */

}

printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);

exit(0);

자식 프로세스와 부모 프로세스 명확하게 주소공간이 완벽하게 분리되어 있다.



■ fork internal : compile results


 


Linux kernel 영역의 메모리 할당은 1G를 할당하며, 윈도우의 경우 2G의 메모리를 할당한다.

메모리 4G기준 User Space 영역(stack ~ text)은 3G의 메모리를 사용한다.


Bss 영역은 심볼과 크기에 대한 정보만 저장하며, 실제로 Bss 영역을 제외하고도 무수히 많은 영역이 존재하며, version up이 될수록 데이터는 추가 된다.

a.out의 format은 지원하는 운영체제에 따라 지원하는 lib가 다르기 때문에 프로그램이 동작되지 않을 수 있다.

리눅스의 경우 Elf format을 사용한다.


fork internal : before fork (after run a.out)

 

Segment 는 인텔에서 사용되는 개념이며, 리눅스의 경우 paging 이라는 개념으로 통용된다.

Process에서 사용중인 가상메모리를 실제 물리메모리로 맵핑 해주는 역할을 Paging이 담당하며, 실제 fork()  수행시 물리메모리 영역의 모든 부분에 대하여 복사하여 사용하지 않는다.


fork internal : after fork

 


text영역은 read only영역이기 때문에 공유해서 사용가능하다. 하지만 stack의 경우 함수의 대한 context switching 정보가 저장 되므로 반드시 복제를 하여 사용한다.

리눅스에서는 stack size가 8메가 이고, Windows의 경우 1메가를 사용한다. 따라서 리눅스 프로그램을 윈도우로 포팅할 경우, 무분별하게 전역변수를 사용하면 오류를 발생하므로 주의해야 한다.


fork internal : with COW (Copy on Write) mechanism

 


해당 이미지는 Copy on Write mechanism에 대한 설명이며, Data 영역이 공유되어 지다가 예를들어 glob라는 지역변수의 증가(glob++)와 같은 변경작업이 이루어지게 되면 data 영역의 복제가 일어난다.


execve internal

 


execute 는 system call을 뜯하며, 수행시 새로운 프로그램으로 동작되어 진다.



다음 수업시간 : 시스템 콜


반응형

'Software > Embedded Linux' 카테고리의 다른 글

MCU(Micro Controller Unit) 그리고 FreeRTOS  (0) 2022.07.04