# 4. 라이브러리와 Hello World

UEFI/EDKII 에서는`SystemTable` 포인터와 `SystemTable->BootServices` 그리고 주요 함수 매개변수인 `ImageHandle`을 사용하게 된다.

따라서 이러한 변수의 접근성을 위해 EDKII 라이브러리에는 `gST`, `gBS`, `gImageHandle`이 전역 선언되어 있다.\
[(https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.c)](https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.c)\
[(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiBootServicesTableLib.h)](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiBootServicesTableLib.h)

```c
EFI_HANDLE         gImageHandle = NULL;
EFI_SYSTEM_TABLE   *gST         = NULL;
EFI_BOOT_SERVICES  *gBS         = NULL;

EFI_STATUS
EFIAPI
UefiBootServicesTableLibConstructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  //
  // Cache the Image Handle
  //
  gImageHandle = ImageHandle;
  ASSERT (gImageHandle != NULL);

  //
  // Cache pointer to the EFI System Table
  //
  gST = SystemTable;
  ASSERT (gST != NULL);

  //
  // Cache pointer to the EFI Boot Services Table
  //
  gBS = SystemTable->BootServices;
  ASSERT (gBS != NULL);

  return EFI_SUCCESS;
}
```

### 1. gST 전역변수를 이용한 문자열 출력하기

```
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
...
  SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
...
```

위와 같이 작성 후 다음과 같은 명령어를 이용해 빌드한다.

```
$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
        --module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
        --arch=X64 \
        --buildtarget=RELEASE --tagname=GCC5
```

그럼 아래와 같은 빌드 에러가 발생한다.

```
error: ‘gST’ undeclared (first use in this function)
```

따라서 `#include`를 이용해 헤더에 라이브러리 정보를 포함 시켜야 한다.

```
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
+ #include <Library/UefiBootServicesTableLib.h>
...
```

`*.dsc` 파일에는 위 라이브러리 정보가 이미 LibraryClasses에 포함되어 있으므로 정상적으로 빌드 할 수 있으며 완성된 코드는 아래와 같다.

```
#include <Library/UefiBootServicesTableLib.h>

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
  gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
  return EFI_SUCCESS;
}
```

### 2. edk2 라이브러리 함수를 이용한 문자열 출력

```
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
+ #include <Library/UefiLib.h>
  #include <Library/UefiBootServicesTableLib.h>
...
  SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
  gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+ Print(L"Bye!\n");
...
```

`Print` 함수는 UefiLib 라이브러리에 포함되어 있으며 이에 대한 정보를 소스 코드와 `*.dsc` 파일에 포함해야 한다.\
[(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiLib.h)](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiLib.h)

만약 `*.dsc` 파일에 해당 정보를 기입하지 않을 경우 다음과 같은 에러러가 발생한다.

```
.c:821: undefined reference to `Print'
error 4000: Instance of library class [MemoryAllocationLib] is not found
```

따라서 다음과 같은 과정을 통해 LibraryClasses를 추가하도록 한다.

```
$ grep UefiLib -r ./ --include=*.inf | grep LIBRARY_CLASS
./MdePkg/Library/UefiLib/UefiLib.inf:  LIBRARY_CLASS                  = UefiLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
$ grep MemoryAllocationLib -r ./ --include=*.inf | grep LIBRARY_CLASS | grep MdePkg
./MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf:  LIBRARY_CLASS                  = MemoryAllocationLib|PEIM PEI_CORE SEC
./MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf:  LIBRARY_CLASS                  = MemoryAllocationLib|DXE_SMM_DRIVER
./MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf:  LIBRARY_CLASS                  = MemoryAllocationLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
```

```
$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
-----
[LibraryClasses]
  ...
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
```

또한 `Hellworld.inf` 에도 LibraryClasses 정보를 추가해준다.

```
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.inf
-----
[LibraryClasses]
  UefiApplicationEntryPoint
+ UefiLib
```

이후 빌드를 진행하면 성공적인 결과를 얻을 수 있다.

```
$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/HelloWorld.efi ~/UEFI_disk/
$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
                     -drive format=raw,file=fat:rw:~/UEFI_disk \
                     -nographic \
                     -net none
                     
UEFI Interactive Shell v2.2
EDK II
UEFI v2.70 (EDK II, 0x00010000)
Mapping table
      FS0: Alias(s):HD0a1:;BLK1:
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Press ESC in 1 seconds to skip startup.nsh or any other key to continue.
Shell> fs0:
FS0:\> HelloWorld.efi
Hello World!
Hello again!
Bye!
FS0:\>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bob-mcd-team.gitbook.io/uefi/uefi-development/uefi-start/4.library-and-hello-world.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
