Неопределенная ссылка при вызове функции c из сборки x86 32 бит [дубликат]

Статические методы следует вызывать в классе, методы экземпляра следует вызывать в экземплярах класса. Но что это значит на самом деле? Вот полезный пример:

Класс автомобиля может иметь метод экземпляра под названием Accelerate (). Вы можете только ускорить автомобиль, если автомобиль действительно существует (был построен), и поэтому это будет метод экземпляра.

Класс автомобиля может также иметь метод подсчета с именем GetCarCount (). Это вернет общее количество созданных (или построенных) автомобилей. Если никакие автомобили не были построены, этот метод вернет 0, но он все равно должен быть вызван, и поэтому он должен быть статическим методом.

26
задан Björn Pollex 13 March 2013 в 10:45
поделиться

4 ответа

вы можете объявить его дважды?

.global bar
.global _bar

Я не писал сборку через некоторое время, но идентификатор .global просто действует как ярлык?

5
ответ дан Carson Myers 20 August 2018 в 09:15
поделиться
  • 1
    Да, это тоже работает. – ephemient 24 June 2009 в 01:24
  • 2
    Директива .global указывает только на то, что этот идентификатор относится к глобальному символу, поэтому его можно заставить работать, если я также определяю две метки для функции, например: .global bar .global _bar bar: _bar: & lt; etc & gt; Помимо дублирования, я также получаю бесполезный «бар». символ в Windows и бесполезный "_bar & quot; символ в Linux. Я надеялся на что-то более чистое, но это действительно работает, поэтому я благодарю вас за предложение. – Maks Verver 24 June 2009 в 15:11

Один из вариантов, хотя и опасен, заключается в том, чтобы убедить GCC опустить требуемое ABI главное подчеркивание.

  • -fleading-underscore Этот параметр и его аналог , -fno-leading-underscore, принудительно изменить способ отображения символов C в объектном файле. Одно использование - это ссылка на устаревший ассемблерный код. Предупреждение: переключатель -fleading-underscore заставляет GCC генерировать код, который не является бинарным, совместимым с кодом, сгенерированным без этого коммутатора. Используйте его для соответствия двоичному интерфейсу приложения, отличного от стандартного. Не все цели обеспечивают полную поддержку этого коммутатора.

Другой, более безопасный вариант - явно указать GCC имя, которое будет использовать.

5.39 Управление именами, используемыми в коде ассемблера

Вы можете указать имя, которое будет использоваться в коде ассемблера для функции или переменной C, написав ключевое слово asm (или __asm__) после объявления следующим образом:

     int foo asm ("myfoo") = 2;

Указывает, что имя, которое будет использоваться для переменной foo в коде ассемблера, должно быть `` myfoo ' rather than the usual \``_foo '.

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

Не имеет смысла использовать эту функцию с нестационарным локальная переменная, так как такие переменные не имеют имен ассемблера. Если вы пытаетесь поместить переменную в определенный регистр, см. Явные реестры . GCC в настоящее время принимает такой код с предупреждением, но, вероятно, будет изменен, чтобы в будущем выпустить ошибку, а не предупреждение.

Вы не можете использовать asm таким образом в функции определение ; но вы можете получить тот же эффект, написав декларацию для функции перед ее определением и помещая там asm, например:

 extern func () asm ("FUNC");

 func (x, y)
      int x, y;
 /* ... */

. Вы должны убедиться, что ассемблер называет вас выберите, не конфликтуйте с другими символами ассемблера. Кроме того, вы не должны использовать имя регистра; что приведет к совершенно недействительному ассемблерному коду. GCC пока не имеет возможности хранить статические переменные в регистрах. Возможно, это будет добавлено.

В вашем случае

extern int bar(int x) asm("bar");

должно указывать GCC, что «bar использует имя asm` `bar` ', хотя это функция ccall ".

24
ответ дан ephemient 20 August 2018 в 09:15
поделиться
  • 1
    Означает ли это, что поведение GCC по умолчанию для Linux должно быть таким, что «C» имена имеют лидирующий знак подчеркивания? Если это так, есть что-то в среде сборки OP, которая отключает ее? – Michael Burr 24 June 2009 в 01:35
  • 2
    В Linux функции, соответствующие стандарту C-вызова (ccall, cdecl, все, что вы хотите назвать), не оформлены. В Windows stdcall - это «default», вызывающие соглашения и функции, следующие за чем-либо еще (например, стандартное соглашение о вызове C). – ephemient 24 June 2009 в 01:46
  • 3
    Как я уже сказал, опции -fleading-underscore и -fno-leading-underscore ничего не делают (они не удаляют подчеркивания в функциях C и не добавляют их для символов сборки); если вы немного поработаете в Google, вы увидите, что у других был такой же опыт, поэтому я получаю впечатление, что эти параметры довольно бесполезны. Предложение asm () является хорошим; Я вполне могу это использовать. Единственным недостатком является то, что сам символ по-прежнему не имеет собственного имени (которое будет _bar в Windows), но по крайней мере я могу ссылаться на обе платформы без дополнительных изменений исходного кода. – Maks Verver 24 June 2009 в 15:15
  • 4
    clang: error: unknown argument: '-no-leading-underscore' clang: error: unknown argument: '-fno-leading-underscore' clang: error: unknown argument: '-fleading-underscore' – anon58192932 19 October 2016 в 13:45

Вы можете использовать препроцессор C для предварительной сборки сборки и использования макроса, чтобы добавить недостающие символы подчеркивания в Windows. Во-первых, вам нужно переименовать файл сборки из bar.s в bar.S (capital 'S'). Это говорит gcc использовать cpp для предварительной обработки файла.

Чтобы добавить недостающие символы подчеркивания, вы можете определить макрос «cdecl» следующим образом:

#if defined(__WIN32__)
# define cdecl(s) _##s
#else
# define cdecl(s) s
#endif

Затем используйте его так: :

.global cdecl(bar)
cdecl(bar):
    movl 4(%esp), %eax
    addl %eax, %eax
    ret

Обратите внимание, что для Mac OSX также требуются ведущие символы подчеркивания, поэтому вы можете обновить первую строку макроса следующим образом:

#if defined(__WIN32__) || defined(__APPLE__)
7
ответ дан Geert 20 August 2018 в 09:15
поделиться

Компиляторы для цели ELF не добавляют по умолчанию подчеркивания подчеркивания. Вы можете добавить -fleading-underscore при компиляции в формат ELF (под Linux). Используйте условное выражение в файле makefile.

Ссылка: http://opencores.org/openrisc,gnu_toolchain (выполните поиск на странице «оставить глобальные имена без изменений»)

4
ответ дан Unsigned 20 August 2018 в 09:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: