Как работает ассемблер? - PullRequest
7 голосов
/ 29 мая 2011

Я ищу краткое описание использования ассемблера при создании машинного кода.

Итак, я знаю, что сборка - это перевод машинного кода 1: 1.Но я запутался в объектном коде и компоновщиках и в том, как они в него помещаются.

Мне не нужен сложный ответ, просто простой подойдет

Ответы [ 2 ]

11 голосов
/ 29 мая 2011

И ассемблер, и компилятор переводят исходные файлы в объектные файлы.

Объектные файлы фактически являются промежуточным этапом перед окончательным выводом исполняемого файла (сгенерированным компоновщиком).

Компоновщик принимает указанные объектные файлы и библиотеки (которые являются пакетами объектных файлов) и разрешает записи перемещения (или исправления).

Эти записи о перемещении создаются, когда компилятор / ассемблер не знает адрес функции или переменной, используемой в исходном коде, и генерирует для него ссылку по имени, которая может быть разрешена компоновщиком.

Например, скажем, вы хотите, чтобы программа выводила сообщение на экран, разделив его на два исходных файла, и вы хотите собрать их отдельно и связать их (например, с помощью системных вызовов Linux x86-64) -

main.asm:

bits 64
section .text
extern do_message
global _start
_start:
    call do_message
    mov rax, 1
    int 0x80 

message.asm:

bits 64
section .text
global do_message
do_message:
    mov rdi, message
    mov rcx, dword -1
    xor rax, rax
    repnz scasb
    sub rdi, message
    mov rax, 4
    mov rbx, 1
    mov rcx, message
    mov rdx, rdi
    int 0x80
    ret

section .data
message: db "hello world",10,0

Если вы соберете их и посмотрите на выходной файл объекта main.asm (например, objdump -d main.o), вы заметите, что у 'call do_message' есть адрес 00 00 00 00 - который недопустим.

0000000000000000 <_start>:
   0:   e8 00 00 00 00          callq  5 <_start+0x5>
   5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
   c:   cd 80                   int    $0x80

Но для 4 байтов адреса делается запись о перемещении:

$ objdump -r main.o
main.o:     file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE 
0000000000000001 R_X86_64_PC32     do_message+0xfffffffffffffffc
000000000000000d R_X86_64_32       .data

Смещение равно «1», а тип - «R_X86_64_PC32», который указывает компоновщику разрешить эту ссылку и поместить разрешенный адрес в указанное смещение.

Когда вы связываете окончательную программу с 'ld -o program main.o message.o', все перемещения разрешаются, и если ничего не разрешено, у вас остается исполняемый файл.

Когда мы 'objdump -d' исполняем, мы видим разрешенный адрес:

00000000004000f0 <_start>:
  4000f0:   e8 0b 00 00 00          callq  400100 <do_message>
  4000f5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
  4000fc:   cd 80                   int    $0x80

Перемещения такого же типа используются как для переменных, так и для функций. Тот же процесс происходит, когда вы связываете свою программу с несколькими большими библиотеками, такими как libc - вы определяете функцию с именем 'main', к которой у libc есть внешняя ссылка - тогда libc запускается перед вашей программой и вызывает вашу функцию 'main', когда вы запускаете исполняемый файл.

1 голос
/ 29 мая 2011

Простое объяснение:

Как только язык ассемблера собран в объектном коде, компоновщик используется для преобразования объектного кода в исполняемый файл команд, которые компьютер может понимать и выполнять. Сгенерированный машинный код может быть интерпретирован контроллером процессора.

...