메모리 주소를 사용하는 데이터 타입은 unsigned long 을 사용해야 한다

 

32bit 에서는 메모리 주소가 4바이트

64bit 에서는 메모리 주소가 8바이트

를 차지하므로 CPU 아키텍처에 따라 데이터 타입의 크기도 달라져야 한다

 

unsigned long 은 32bit 에서는 4바이트 64bit 에서는 8바이트가 되므로

 

메모리 주소를 담을때 사용가능하다.

 

ex)

char c;

unsigned long addr = (unsigned long)&c;

shared library 이해 및 만들기


1) shared library

  - Windows 에서는 .dll , Linux, macos 에서는 .so


2) soname

  - compile time 에서는 .so 를 참조하며 runtime 시 .so.{version} 의 파일을 참조

  - 실제 library 파일은 .so.{major}.{minor}... 등의 형태로 사용

[참고: https://kldp.org/node/85366]


3) 빌드방법

 - Linux :

    . gcc -c -fPIC -o output source

    . gcc -shared -Wl,-soname,"libraryname".so.{major version} -o "libraryname".so.{major}.{minor} object


 - macos :

    . gcc -shared -Wl,-install_name,"libraryname".so.{major version} -o "libraryname".so.{major}.{minor} object


4) soname 과 ABI

  - library major 변경이 아닌 경우 재빌드 없이 사용할수 있게 해줌

  - libwaintman.so.1.1 라이브러리가 soname 이 libwaintman.so.1 일때,

    TEST 모듈이 libwaintman.so.1.1 을 참조하게 되면 compile 타임에 libwaintman.so 를 참조함

    . libwaintman.so --> libwaintman.so.1

    . libwaintman.so.1 --> libwaintman.so.1.1

    일 때, TEST 모듈은 빌드될때 libwaintman.so.1.1를 참조하게 됨

 

    TEST 모듈이 실행 될 때 soname 인 libwaintman.so.1 을 찾게 됨

    이 때 libwiantman.so.1 이 libwaintman.so.1.3 버전을 가리키고 있어도 정상적으로 실행이 됨


    정상적으로 실행이 안될 경우 libwaintman.so.1.1 과 libwaintman.so.1.3 은 major 변경이 일어난 경우 이므로

    libwaintman.so.1.3 soname 은 libwaintman.so.2 와 같이 변경이 되어야 함.

    이렇게 되면 TEST 모듈이 실행 될 때 libwaintman.so.1 이 시스템에 없으므로 실행이 되지 않으며

    TEST 를 libwaintman.so.2 를 포함해서 재빌드 해야 됨

macOS 10.13 High Sierra 에서는 기본적인 dyld 는 start 함수가 함수의 시작점이 된다


어셈블러로 start 함수를 작성하여 다른 라이브러리 import 없이 프로그램을 실행할 수 있다


코드 작성

hello2.s

.macosx_version_min 10, 7
.globl start
.text

start:
    mov $0x2000004, %rax
    mov $1, %rdi
    movabs $msg, %rsi
    mov $len, %rdx
    syscall

    mov $0x2000001, %rax
    mov $0x0, %rdi
    syscall

.data

msg:
    .ascii "Hello, World!\n"
    len = . - msg
 


macOS 10.8 부터는 ld 에서 강제적으로 main 함수를 호출하고 있어 macosx_version_min 을 10.7 로 강제로 세팅한다


ld 코드 확인 ( https://opensource.apple.com/source/ld64/ld64-274.2/src/ld/Options.cpp.auto.html )


void Options::reconfigureDefaults()
{
.................

switch
( fOutputKind ) { case Options::kDynamicExecutable: if ( fEntryPointLoadCommandForceOn ) { fEntryPointLoadCommand = true; if ( fEntryName == NULL ) fEntryName = "_main"; } else if ( fEntryPointLoadCommandForceOff ) { fNeedsThreadLoadCommand = true; if ( fEntryName == NULL ) fEntryName = "start"; } else { // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS if ( minOS(ld::mac10_8, ld::iOS_6_0) || fTargetIOSSimulator ) { fEntryPointLoadCommand = true; if ( fEntryName == NULL ) fEntryName = "_main"; if ( strcmp(fEntryName, "start") == 0 ) { warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version"); fEntryName = "_main"; } } else { fNeedsThreadLoadCommand = true; if ( fEntryName == NULL ) fEntryName = "start"; } } break;

.....................

 



macos 10.8 부터 강제로 _main 으로 점프하게 되어 있으며 ld 옵션 -e 옵션으로 지정해 주는 것도 막고 있다.


빌드 방법

as -c hello2.s -o hello2.o

ld -macosx_version_min 10.7 -o hello2 hello2.o


10.8 이상에서는

Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for inferred architecture x86_64 



_main 함수가 없다는 에러가 발생한다


혹은 no_new_main 옵션을 추가하면 최신 버전에서도 빌드가 잘 된다


ld -macosx_version_min 10.13 -no_new_main -o hello2 hello2.o


해당 옵션은 man page 에서는 보이지 않는다.


아래에 구현되어 있다

            else if ( strcmp(arg, "-new_main") == 0 ) {
                fEntryPointLoadCommandForceOn = true;
                cannotBeUsedWithBitcode(arg);
            }   
            else if ( strcmp(arg, "-no_new_main") == 0 ) {
                fEntryPointLoadCommandForceOff = true;
                cannotBeUsedWithBitcode(arg);
            }    


참조: https://stackoverflow.com/questions/24841283/how-can-i-set-a-custom-c-entry-point-with-clang-on-os-x-mavericks

GAS (GNU Assembler)


macOS 에서는 as 컴파일러 사용.

macOS 에서는 clang에 포팜된 컴파일러가 사용된다


Hello, World! 출력 코드 작성


Reference : http://www.idryman.org/blog/2014/12/02/writing-64-bit-assembly-on-mac-os-x/


hello1.s 작성


.globl _main
.text

_main:
    mov $0x2000004, %rax
    mov $1, %rdi
    movabs $msg, %rsi
    mov $len, %rdx
    syscall
    ret

.data

msg:
    .ascii "Hello, World!\n"
    len = . - msg
 


64bit assembly 에서는 system call 방식이 int 0x80 에서 syscall 로 변경되었다.

또한 syscall 번호도 base 0x2000000 이 추가된다


syscall 번호 확인 : https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/kern/syscalls.master.auto.html


4	AUE_NULL	ALL	{ user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } 


rax 레지스터에 write syscall 인 4 + base 추가

rdi 레지스터에 stdout 인 1 추가 (fd)

rsi 레지스터에 "Hello, World!\n" 가 저장된 주소 추가 (cbuf)

rdx 레지스터에 길이 값 추가 (nbyte)


syscall 실행


ret 호출로 마무리

macOS 에서 링킹 시 crt1.o 를 같이 import 해야 한다


crt1.o 에는 macOS loader 에서 실행하는 start() 함수가 구현되어 있다


https://opensource.apple.com/source/Csu/Csu-85/


start.s 를 보면 start 함수가 arhictecture 에 따라 구현되어 있는 것을 확인 할 수 있다.


#if __x86_64__
start:	pushq	$0		    # push a zero for debugger end of frames marker
	movq	%rsp,%rbp	    # pointer to base of kernel frame
	andq    $-16,%rsp	    # force SSE alignment
	movq	8(%rbp),%rdi	    # put argc in %rdi
	leaq	16(%rbp),%rsi	    # addr of arg[0], argv, into %rsi
	movl	%edi,%edx	    # copy argc into %rdx
	addl	$1,%edx		    # argc + 1 for zero word
	sall	$3,%edx		    # * sizeof(char *)
	addq	%rsi,%rdx	    # addr of env[0], envp, into %rdx
#if OLD_LIBSYSTEM_SUPPORT	
	call	__start		    # call _start(argc, argv, envp)
	hlt			    # should never return
#else
	movq	%rdx,%rcx
	jmp	Lapple2
Lapple:	add	$8,%rcx
Lapple2:cmpq	$0,(%rcx)	    # look for NULL ending env[] array
	jne	Lapple		    
	add	$8,%rcx		    # once found, next pointer is "apple" parameter now in %rcx
	call	_main
	movl	%eax,%edi	    # pass result from main() to exit() 
	call	_exit		    # need to use call to keep stack aligned
	hlt
#endif
#endif // __x86_64__ 


call _main 부분에서 우리가 흔히 만드는 main 함수를 call 하는 부분이 되며

call _exit 를 통해 프로세스를 종료한다


main 함수에서 exit 를 호출하면 call _exit 전에 프로세스가 종료된다


<stdlib.h> 에 있는 exit 함수와 start.s 에서 call _exit 로 호출되는 함수는 동일하다


컴파일 : 소스코드에서 오브젝트 코드를 만드는 것

링킹 : 목적코드에서 실행가능한 형태 혹은 라이브러리로 만드는 것


빌드 : 컴파일 + 링킹



[Linux (ubuntu) 에서 GCC 를 이용한 컴파일 및 링킹]


1) 컴파일 : gcc -c test.c

2) 링킹 : ld -o test /usr/lib/x86_64-linux-gnu/crt1.o test.o -lc /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o -dynamic-linker /lib64/ld-linux-x86-64.so.2


설명:

-lc : libc.a 를 포함 ( printf 함수와 같은 C Library 를 사용할수 있게 한다)


libc : C Library

glibc : GNU C Library


crt1.o , crti.o, crtn.o : _start, _init 함수와 main 함수로의 jump 를 해주는 라이브러리를 가지고 있다


-dynamic-linker /lib64/ld-linux-x86-64.so.2 : ELF 포맷을 실행해주는 dynamic linker 를 지정한다


[macOS (10.13) 에서 GCC 를 이용한 방법]


1) 컴파일 : gcc -c test.c

2) 링킹 : ld -o test -lSystem test.o /usr/lib/crt1.o


-lSystem : C Library import ( libSystem.dylib )

/usr/lib/crt1.o : main 으로 jump 해주는 라이브러리 포함 ( com.apple.pkg.DevSDK_macOS1013_Public )

(source code : https://opensource.apple.com/source/Csu/Csu-85/)

출처 : https://github.com/skaht/Csu-85


libSystem.dylib : C Library ( com.apple.pkg.Core 에 포함 )


확인 방법

pkgutil --file-info /usr/lib/libSystem.dylib

pkgutil --file-info /usr/lib/crt1.o



* 보통은 gcc -o test test.c 명령으로 한번에 실행파일 생성이 가능하다



Makefile 에 변수 할당 방법


1) variable = define

2) variable := define


1) 의 방법은 변수를 읽는 시점에 값이 정해지며, 2)의 방법은 변수를 assign 하는 시점에 값이 정해진다


할당된 변수 사용법은

$(variable)


출처: https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors

macOS 10.13 high sierra 에서 gst-plugins-good-1.12.3 버전 osxvideosink 사용시

illegal instruction : 4 에러 발생


출처: https://bugzilla.gnome.org/show_bug.cgi?id=786047


해결방법 : gst-plugins-good sys/osxvideo/osxvideosink.m 파일

_CFRunLoopSetCurrent(CFRunLoopGetMain()) 라인 위에

CFRetain(CFRunLoopGetCurrent()) 라인 추가


OS : macOS 10.13 (high sierra)

gst-plugins-good 1.12.3


osxvideosink error


fix : https://bugzilla.gnome.org/show_bug.cgi?id=786047


sys/osxvideo/osxvideosink.m


nsAppThread


insert CFRetain(CFRunLoopGetCurrent());

below _CFRunLoopSetCurrent(CFRunLoopGetMain());


macOS 의 구조


[출처: https://en.wikipedia.org/wiki/Architecture_of_macOS]

Diagram of Mac OS X architecture


[Core OS : Darwin]

 - Unix(BSD) 계열 OS

 - XNU kernel 사용

   : hybrid kernel. (BSD + Mach)


Darwin 은 Unix(BSD) 계열 OS 로 커널은 xnu 를 사용하고 있음

XNU kernel + system utilities = Darwin


Linux 와 비교해 보면, Darwin 과 같은 Level 은 리눅스


리눅스를 기반으로 한 배포판인 ubuntu, fedora 플랫폼이 macOS


Darwin 과 XNU kernel 은 open source 로

Darwin 을 이용하여 macOS 와 다른 배포판을 만들수 있음 ( ubuntu, fedora, centos 등 여러가지 platform 이 있는 것 처럼)

하지만 Darwin 은 Unix(BSD) 계열 OS 로 driver 개발등 어려운 점이 있음


(https://www.quora.com/Whats-the-difference-between-Mac-OS-X-Darwin-OS-and-a-popular-Linux-distribution-like-Ubuntu-What-can-be-done-on-Darwin)


XNU kernel source code : https://opensource.apple.com/source/xnu/



Core OS 위에

Core Services, Media, Cocoa Application 으로 구성.

User Application 은 Cocoa Framework 를 사용하여 개발 가능.


macOS 에서 사용하는 GUI 는 Aqua. ( https://en.wikipedia.org/wiki/Aqua_(user_interface) )

MacOS Architecture v2






Pintos 란

 - 스탠포드에서 만든 교육용 OS

 - cs140 수업

    http://www.scs.stanford.edu/17wi-cs140/reference/index.html


PintOS 설치 - macOS 10.13 High Sierra


 1.  Prerequires

    . homebrew (https://brew.sh/)

        - gcc 4.9

        - qemu

          (bochs 대신 qemu 를 사용한다)


2. Download pintos

git clone http://cs140.stanford.edu/pintos.git pintos

 


3. Build pintos

    . PintOS 빌드하려면 32bit gcc 4.1 버전이 필요함


    - 32bit gcc 4.1 빌드

       a) http://wiki.osdev.org/Cross-Compiler_Successful_Builds

         gcc 4.1 버전과 맞는 binutils 설치 (binutils-2.17)

        -

git clone git://sourceware.org/git/binutils-gdb.git

git checkout tags/binutils-2_17

        - build

./configure --prefix=$PREFIX --target=i386-elf --disable-multilib --disable-nls --disable-werror

make

make install


        - i386-elf-ld 실행 확인

      b) gcc 4.1 설치

컴파일러는 brew로 설치한 gcc-4.9를 이용 (최신 버전의 gcc 혹은 clang 으로는 gcc-4.1 을 빌드할수 없음)

git clone git://gcc.gnu.org/git/gcc.git

git checkout tags/gcc-4_1_0-release

CC=gcc-4.9 ./configure --prefix=$PREFIX --target=i386-elf --disable-multilib --disable-nls --disable-werror --without-headers --enable-languages=c,c++

make all-gcc install-gcc


      - i386-elf-gcc 실행 확인


   - PintOS Make.config 수정

ifneq (0, $(shell expr `uname -m` : '$(X86_64)'))
    CC = $(CCPROG) -m32
    LD = ld -melf_i386
    OBJCOPY = objcopy
else
 

이 부분을

fneq (0, $(shell expr `uname -m` : '$(X86_64)'))

     CC = i386-elf-gcc
     LD = i386-elf-ld
     OBJCOPY = i386-elf-objcopy

else


로 수정

i386-elf-gcc (4.1) 컴파일러로 빌드하기위한 옵션


. 동작확인

pintos --qemu -- run alarm-multiple 



+ Recent posts