2013-04-23 2 views
3

У меня есть этот простой исходный C-код:Вызов подпрограммы сборки из исходного кода C

#include <stdio.h> 

extern int Sum(int,int); 

int main() 
{ 
    int a,b,s; 
    a=1 , b=2; 
    s = Sum(a,b); 
    return 0; 
} 

и у меня есть этот s.asm, который определяет функцию _Sum:

global _Sum 

    _Sum: 

     push ebp    ; create stack frame 
     mov  ebp, esp 
     mov  eax, [ebp+8] ; grab the first argument 
     mov  ecx, [ebp+12] ; grab the second argument 
     add  eax, ecx  ; sum the arguments 
     pop  ebp    ; restore the base pointer 
     ret 

теперь я компилировалось .asm с помощью:

nasm s.asm -f elf -o s.o 

и скомпилирован и связала .c файл с помощью:

gcc s.o test.o -o testapp 

это результат:

/tmp/ccpwYHDQ.o: In function `main': 
test.c:(.text+0x29): undefined reference to `Sum' 
collect2: ld returned 1 exit status 

Так что это проблема?

Я использую Ubuntu-Linux

Любая помощь будет принята с благодарностью, спасибо

[РЕШИТЬ]: я проверил с нм файл test.o и ожидал найти символ «Сумма» а не «_Sum», так что это решило проблему.

+2

Сверху моей головы ваш прототип суммы неверен. 'extern int Sum (int, int);' – RageD

+2

Вам, вероятно, нужно поставить 'global _Sum' где-то на стороне asm – harold

+0

Я попробовал' global _Sum' вместо '_Sum', я получил то же сообщение об ошибке @harold – hshihab

ответ

4

Насколько я могу судить по вашему вопросу, вы перезаписываете свой объектный файл, который был получен с ассемблера s.o программой C. Таким образом, у вас больше нет процедуры ассемблера.

Вы, вероятно, следует написать

Сформировать файл s.o объекта

nasm s.asm -f elf -o s.o 

генерировать test.o (ваша команда создали еще кого-н)

gcc test.c -c 

Link приложение

gcc s.o test.o -o testapp 

(я выбрал TestApp в качестве выходного двоичного файла, потому что test часто очень плохо название программы, он сталкивается с командой Unix test)

+0

хорошо, я сделал два изменения, которые были упомянуты выше (изменение прототипа и глобальной декларации) теперь мои первые 2 строчки в .asm файлов как этот 'глобальной _Sum _Sum: ' и я скомпилирован и связан как и предложил, он все равно генерирует ту же ошибку – hshihab

+0

Вы уверены, что вам нужно добавить идентификатор с подчеркиванием? Я не занимался ассемблером в течение длительного времени, но я помню, что это было не всегда так, и это зависело от настроек среды или параметра. Вы можете проверить с помощью 'nm', что на самом деле выглядит символ, который ожидает код C. –

+0

Я просто проверил его с помощью nm и произвел '00000000 T _Sum' – hshihab

7

В типичных ассемблерах метки по умолчанию являются локальными. Для того, чтобы сказать ассемблеру, чтобы сделать их видимыми для внешних подпрограмм, вы должны добавить объявление, например:

.globl _Sum 

Кроме того, объявить подпрограмму правильно C. Это не является причиной вашей ошибки связи, но может привести к другой проблемы:

extern int Sum(int, int); 

Для полноты информации, благодаря комментариям: не перезаписывайте свои объектные файлы. Вы можете собрать, скомпилировать и связь с:

nasm s.asm -f elf -o s.o 
gcc test.c s.o -o test 

(Это имена исполняемый «тест», и вы, вероятно, придется выполнить его с «./test», чтобы отличить «тест» в директории с команда «тест». Возможно, вы более счастливы выбрать другое имя.)

Для образовательных целей: Если у вас есть инструмент nm в вашей системе, выполните команду nm s.o. Он может показать вам что-то вроде:

00000000 t _Sum 

t означает, что _Sum является локальной метка в секции коды. (Раздел кода также называется текстовым разделом, следовательно, t.) После добавления объявления .globl и сборки нового источника, nm s.o должен показывать вместо этого верхний регистр T. Верхний индекс указывает, что метка внешне видима.

+0

- правильный синтаксис: «.globl» или «global»? – hshihab

+0

и как я могу установить этот инструмент? спасибо – hshihab

+0

@hshihab: Синтаксис зависит от вашего ассемблера. Я бы попробовал «.globl» и «.global», затем обратитесь к документации. –

0

Это лучше объявить ассемблера встроенный в гр файлов. Вот пример из моего кода:

bool KxMutex::tryLock_i() 
{ 
#ifdef KX_MUTEX_ASM 
    int oldLock; 
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 
    asm volatile (
    "movl $1,%%eax\n\t" 
    "xchg %%eax,%0\n\t" 
    "movl %%eax,%1\n\t" 
    : "=m" (mLock), "=m" (oldLock) 
    : 
    : "%eax", "memory" 
    ); 
#elif defined(__GNUC__) && (defined(__ppc__)) 
    int newLock = 1; 
    asm volatile (
    "\n1:\n\t" 
    "lwarx %0,0,%1\n\t" 
    "cmpwi 0,%0,0\n\t" 
    "bne- 2f\n\t" 
    "stwcx. %2,0,%1\n\t" 
    "bne- 1b\n\t" 
    "isync\n" 
    "2:\n\t" 
    : "=&r" (oldLock) 
    : "r" (&mLock), "r" (newLock) 
    : "cr0", "memory" 
); 
#endif 
    return (oldLock == 0); 
#else // !KX_MUTEX_ASM 
    return (pthread_mutex_trylock((pthread_mutex_t*)this) ? false : true); 
#endif // !KX_MUTEX_ASM 
} 

Есть много преимуществ:

  1. Вы не должны управлять фреймом стека, возвращающих значения и т.д. самостоятельно.
  2. компилятор может встраивать функцию, когда это необходимо, так как она контролирует соглашение о вызовах
  3. Вы можете ссылаться с языка символов непосредственно в коде .asm
  4. Это легче иметь различные версии ASM для различных платформ, контролируемых из те же макросы и определения c.
  5. Все С и С ++ модификаторы функции работают - ехЬегп, статические, рядный т.д.
  6. Компилятор все еще может сделать проверку типа на ваших аргументов функции, убедитесь, что функция вызывается правильно и т.д.
  7. Вы можете защитить ваш переменные с константой при необходимости.
Смежные вопросы