Как связать сборку ELF32 и файлы C?

#c #assembly #compilation #nasm

#c #сборка #Сборник #nasm

Вопрос:

Я написал простую часть программного обеспечения для сборки (nasm) и простое приложение на C. Мой код на C вызывает функцию из ассемблерного кода, но я не знаю, как скомпилировать код на C, не получая ошибку ‘undefined reference’ из строки ‘extern int Sum();’.

C-код:

 #include <stdio.h>

extern int Sum();

main()
{
  int a1, a2, x;

  x = Sum(a1, a2);
  printf("value of x is: %dn", x);
}
  

Ассемблерный код:

 global _Sum

_Sum:
    push ebp
    mov  ebp, esp

    mov  eax, [ebp 8]
    mov  ecx, [ebp 12]
    add  eax, ecx
    pop  ebp
    ret
  

Как бы мне скомпилировать эти два файла по отдельности и впоследствии связать их вместе в один унифицированный файл?

Комментарии:

1. Я знаю, что этот вопрос устарел: Однако для тех, кто приходит сюда — ссылка на код и книгу, на которую я ссылался в своем ответе ниже, является отличным ресурсом для изучения сборки. Надеюсь, у вас будет возможность это проверить!

Ответ №1:

Вы должны собрать файл .asm, чтобы получить файл .o (object), как вы сказали, вы уже сделали. Затем вы должны скомпилировать (но не связать) файл .c, чтобы получить другой файл .o, подобный этому:

 gcc -o whatever.o -c whatever.c
  

Затем вы должны связать их вместе, вот так:

 gcc whatever.o asm.o
  

Тогда компоновщик будет запущен со всем объектным кодом сразу и должен быть в состоянии разрешить необходимые ссылки.

Комментарии:

1. Спасибо за ответ, но это просто выдает мне эту ошибку: main.o: В функции main': main.c:(.text 0x1f): undefined reference to Sum’ collect2: ld возвращен статус выхода 1

2. …когда вы запускаете первую команду или вторую? Можете ли вы вставить все команды, которые вы выполняете, до первого сбоя?

3. Кроме того, можете ли вы вывести содержимое вашего объектного файла с ассемблерным кодом с помощью objdump или аналогичного, чтобы мы могли видеть, какие символы он на самом деле содержит?

4. 1-й: gcc -c main.c (результат: main.o) 2-й: nasm -f elf func.asm (результат: func.o) 3-й: gcc main.o func.o (результат: main.o: В функции main': main.c:(.text 0x1f): undefined reference to Sum’ collect2: ld возвращен статус выхода 1)

5. objdump -t функция.o: формат файла elf32-i386 ТАБЛИЦА СИМВОЛОВ: 00000000 l df ABS 00000000 func.asm 00000000 l d .текст 00000000 .текст 00000000 g .текст 00000000 _Sum

Ответ №2:

В ABI, используемом с ELF, имена C не искажаются инициалом _ .

Комментарии:

1. искажение диктуется компиляторами, и GCC искажает имена функций C с начальным подчеркиванием

2. @Foo, GCC делает то, что хочет целевой ABI, и я не знаю ни одного ABI, используемого с ELF, который искажает имена C с помощью инициала _ . GCC при необходимости приведет к сбоям при нацеливании на другой ABI.

Ответ №3:

Для тех, кто ищет здесь: ознакомьтесь с кодом и закажите здесьhttp://www.drpaulcarter.com/pcasm/index.php : Загрузите примеры Linux здесь : Файл, к которому вы хотели бы обратиться, — first.asm — (Скомпилируйте его в соответствии с архитектурой: 32-разрядный пример ниже)

 nasm -f elf -d ELF_TYPE asm_io.asm
nasm -f  elf32 first.asm 
gcc -o first first.o driver.c asm_io.o
  

Ответ №4:

Есть две возможности решить эту проблему, скомпилировать исходный код C как C (НЕ C ), чтобы скомпилировать его как C, вы должны присвоить ему расширение .c

Второй способ, в коде C (расширение .cpp) имена искажаются, при компиляции кода C используйте шестнадцатеричный редактор, чтобы заглянуть в объектный файл и выполнить поиск Sum. В моем случае имя становится _Z3Sumii . Если вы измените имя в исходном коде ассемблера на это, вы обнаружите, что это работает.

Также измените extern инструкцию в исходном коде C на следующую, поскольку она принимает два параметра типа int , например, extern int Sum(int, int);

   global _Z3Sumii
_Z3Sumii:
  push ebp
  mov  ebp, esp
  mov  eax, [ebp 8]
  mov  ecx, [ebp 12]
  add  eax, ecx
  mov  esp, ebp
  pop  ebp
  ret
  

Для компиляции:

 gcc -c file.cpp
nasm -f elf32 sum.asm -o sum.o
gcc file.o sum.o -o file
  

Ответ №5:

Самый простой способ — использовать набор инструментов GCC для получения кода на ассемблере вашей программы на C, затем вручную собрать оба файла на ассемблере и связать их.

Комментарии:

1. Спасибо. Но есть ли способ связать код вместе без использования сборки, сгенерированной GCC?

2. Вы говорите о двух разных этапах процесса компиляции — сборке и связывании. Чтобы связать файлы вручную, вы можете использовать стандартную утилиту ‘ld’.

3. Я знаю это, но проблема в том, что когда я собираю файл .asm. Нет проблем. Я получаю файл .o. Когда я компилирую файл .c с помощью GCC, он выдает мне ошибку о неопределенной ссылке на ‘Sub’, но я не могу связать файлы и тем самым устранить ошибку до компиляции файла .c. Это моя дилемма.

4. Поскольку ‘Sub’ помечен как external , все, что вам нужно сделать, это ограничить компоновщик в GCC toolchain и связать файлы вручную. Кроме того, в GCC должна быть опция для привязки внешних файлов к коду.

5. Что касается ограничения компоновщика, я компилирую с помощью этой команды: gcc -c main.c, и затем он компилируется нормально, а затем я собираю ассемблерный код с помощью этой команды: nasm -f elf func.asm, и, наконец, я связываю вот так: ld main.o func.o -o program, но это выдает мне эту ошибку: ld: предупреждение: не удается найти символ ввода _start; значение по умолчанию 0000000008048080 main.o: В функции main': main.c:(.text 0x1f): undefined reference to Sum’ main .c:(.text 0x35): неопределенная ссылка на `printf’

Ответ №6:

В ваших обстоятельствах:

 nasm -f elf -o sumasm.o sumasm.asm
gcc -o sum sumasm.o sum.c 
  

вам может понадобиться elf32