# Компоновка и линковка

При стандартной компиляции проекта создается полноценный ELF файл, происходит выравнивание по границам страниц памяти. При использовании указателя global main подключается стартовый код стандартной библиотеки C.

**Точки входа.**

Точка входа определяется значением global &lt;что-то&gt; Варианты точек входа.

<table border="1" id="bkmrk-%D0%A2%D0%B8%D0%BF-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B-%D0%A0%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5" style="width: 96.4286%; border-collapse: collapse; border-color: rgb(0, 0, 0); border-style: solid;"><thead><tr><th style="width: 31.4779%; border-color: rgb(0, 0, 0);">Тип программы</th><th style="width: 39.1555%; border-color: rgb(0, 0, 0);">Рекомендуемая точка входа</th><th style="width: 29.3666%; border-color: rgb(0, 0, 0);">Компиляция</th></tr></thead><tbody><tr><td style="width: 31.4779%; border-color: rgb(0, 0, 0);">Самостоятельная Linux</td><td style="width: 39.1555%; border-color: rgb(0, 0, 0);">\_start</td><td style="width: 29.3666%; border-color: rgb(0, 0, 0);">ld</td></tr><tr><td style="width: 31.4779%; border-color: rgb(0, 0, 0);">С использованием libc</td><td style="width: 39.1555%; border-color: rgb(0, 0, 0);">main</td><td style="width: 29.3666%; border-color: rgb(0, 0, 0);">gcc</td></tr><tr><td style="width: 31.4779%; border-color: rgb(0, 0, 0);">GUI Windows</td><td style="width: 39.1555%; border-color: rgb(0, 0, 0);">WinMain</td><td style="width: 29.3666%; border-color: rgb(0, 0, 0);">Visual Studio</td></tr><tr><td style="width: 31.4779%; border-color: rgb(0, 0, 0);">DLL Windows</td><td style="width: 39.1555%; border-color: rgb(0, 0, 0);">DllMain</td><td style="width: 29.3666%; border-color: rgb(0, 0, 0);">Visual Studio</td></tr><tr><td style="width: 31.4779%; border-color: rgb(0, 0, 0);">Ядро ОС</td><td style="width: 39.1555%; border-color: rgb(0, 0, 0);">kmain</td><td style="width: 29.3666%; border-color: rgb(0, 0, 0);">специальный линкер</td></tr><tr><td style="width: 31.4779%; border-color: rgb(0, 0, 0);">Пользовательская</td><td style="width: 39.1555%; border-color: rgb(0, 0, 0);">любое имя</td><td style="width: 29.3666%; border-color: rgb(0, 0, 0);">ld -e имя</td></tr></tbody></table>

**Варианты компиляции**

**Команды консоли**

```bash
nasm -f elf64 hello.asm -o hello.o
ld -o hello hello.o
```

В случае использования точки входа \_start

**make файл**

```
hello: hello.o
	gcc -o hello hello.o -no-pie
hello.o: hello.asm
	nasm -f elf64 -g -F dwarf hello.asm -l hello.lst
```

Компилирование происходит командой make,

**Процедура поиска библиотек**

Директивой extern printf говорится компилятору: "я знаю где эта функция, делай все остальное".

```
nm -D /lib/x86_64-linux-gnu/libc.so.6 # просмотр списка функций в библиотеке
# Какие библиотеки использует программа
ldd program

# Посмотреть неразрешенные символы в объектном файле
nm -u program.o

# Посмотреть символы в исполняемом файле
nm program | grep printf
```

**Объединение нескольких файлов.**

**Вариант 1** - директива include. Она фактически вставляет текст одного файла в другой файл. Например есть файл sum.asm который мы будем включать в файл hello.asm.

```
section .text
; Функция возвращает сумму чисел
; Принимает два параметра:
; rdi - первое число 
; rsi - второе число
; Результат функции возвращается через регистр rax
sum:
    mov rax, rdi      ; результат в rax
    add rax, rsi
    ret
```

Тогда hello.asm

```
global _start
 
section .text
%INCLUDE "sum.asm"
_start:
    mov rdi, 33
    mov rsi, 44
     
    call sum
    mov rdi, rax         ; для проверки результата помещаем сумму из RAX в RDI
    mov rax, 60
    syscall
```

**Вариант 2.** Раздельная компиляция. В этом случае доступные извне метки (функции, данные) объявляются с помощью директивы global. Файл sum.asm:

```
global sum  ; делаем функцию sum доступной извне
 
section .text
; Функция возвращает сумму чисел
; Принимает два параметра:
; rdi - первое число 
; rsi - второе число
; Результат функции возвращается через регистр rax
sum:
    mov rax, rdi      ; результат в rax
    add rax, rsi
    ret
```

Файл hello.asm

```
global _start
 
extern sum      ; функция sum расположена где-то во вне
 
section .text
_start:
    mov rdi, 33
    mov rsi, 44
     
    call sum
    mov rdi, rax         ; для проверки результата помещаем сумму из RAX в RDI
    mov rax, 60
    syscall
```

Сначала скомпилируем файл sum.asm:

```
nasm -f elf64 sum.asm -o sum.o
```

Затем скомпилируем файл hello.asm:

```
nasm -f elf64 hello.asm -o hello.o
```

В итоге у нас получится два разных объектных файла - sum.o и hello.o. Скомпонуем их в один исполняемый файл:

```
ld hello.o sum.o -o hello
```