Скомпілюйте та запустіть програму без main () в C


79

Я намагаюся скомпілювати та запустити наступну програму без main()функції в C. Я скомпілював свою програму, використовуючи наступну команду.

І компілятор дає попередження

Без проблем. тоді я запустив виконуваний файл (a.out), обидва printfоператори успішно надрукували, а потім отримали помилку сегментації .

Отже, моє запитання: Чому помилка сегментації після успішного виконання операторів друку?

мій код:

вихід:

Hello World...
Successfully run without main...
Segmentation fault (core dumped)

Примітка:

Тут -nostartfilesпрапорець gcc заважає компілятору використовувати стандартні файли запуску під час зв’язування


37
Я здивований, що це взагалі працює. Чесно кажучи, я вважаю таке поводження лінкера помилковим (або принаймні поганою річчю): не було точки входу, тому лінкер просто галюцинував його від будь-якої зручної функції. Пляма.
imallett

4
@imallett, принаймні лінкер був досить люб'язним, щоб привернути увагу до нього застереженням і пояснити, які резервні дії він робив! Ви маєте рацію, що це може бути краще помилкою, а не лише попередженням.
Тобі Спейт,

Чому б ви не використовували main?
Пітер Б,

4
@PieterB - Не надто стосується дискусії про Unices, але точка входу для програм Windows не обов'язково main, але WinMainабо wWinMain.
StoryTeller - Unslander Monica

@StoryTeller насправді як в Windows, так і в Linux ви можете встановити довільну точку входу: для Linux ldце буде -eопцією, для лінкера MSVC Windows - /ENTRYопцією.
Руслан

Відповіді:


131

Давайте подивимось на згенеровану збірку вашої програми:

Зверніть увагу на retтвердження. Точкою входу вашої програми визначено nomain, що з цим все гаразд. Але коли функція повертається, вона намагається перейти до адреси у стеці викликів ..., яка не заповнена. Це незаконний доступ, і слід помилка сегментації.

Швидким рішенням було б зателефонувати exit() в кінці вашої програми (і припускаючи, що C11 ми можемо також позначити функцію як _Noreturn):

Насправді, тепер ваша функція поводиться майже як звичайна mainфункція, оскільки після повернення з main, exitфункція викликається із mainзначенням return.


6
Я думаю, що є деякі комбінації архітектури / ОС, де ви можете просто «повернутися» з програми; Виконавчі файли MS-DOS .COM? У будь-якому випадку, ми глибоко зайнялися поведінкою, яка залежить від реалізації.
pjc50,

4
@ pjc50 - Ми справді. Хоча шлях в OP пропонував варіант Unix. Це в поєднанні з популярністю певних архітектур та наборів інструкцій було єдиною причиною, за якою я почував себе комфортно представляти згенеровану збірку у відповіді.
StoryTeller - Unslander Monica

1
Просто спостереження. -nostartfilesтакож може зробити бібліотеку C непридатною для використання. Без запуску C, виконані наступні виклики функцій бібліотеки C, можуть несподівано вийти з ладу. У Linux, якщо вам потрібно було компілювати, -nostartupfilesі -staticви можете виявити, що програма винить. Є C бібліотека MUSL , які не вимагають від передньої ініціалізації, які призначені для роботи в цьому середовищі.
Michael Petch

22

У C, коли функції / підпрограми викликаються, стек заповнюється як (у порядку):

  1. Аргументи,
  2. Зворотня адреса,
  3. Локальні змінні, -> верх стека

main (), будучи початковою точкою, ELF структурує програму таким чином, що будь-які вказівки, які надходять спочатку, будуть спонукані першими, в цьому випадку printfs є.

Тепер програма начебто усічена без адреси повернення АБО, __end__і фактично вона передбачає, що все, що є в стеці в цьому ( __end__) місці, є адресою повернення, але, на жаль, її немає, а отже, вона аварійно завершує роботу.


4
Чи порядок даних стека визначений стандартом С? Я думав, що це
залежить від

1
Ось чому я згадав ELF (формат файлу, що виконується та зв’язується), це генерується шляхом перехресного компілювання для певного типу ARCH у необхідній ОС.
Milind Deore

1
Щоб бути вибагливим, ви можете використовувати формат ELF навіть у системах без стека. Одним із прикладів такої системи є Freescale RS08 з компілятором Codewarrior, який генерує файли зв’язування ELF.
Лундін,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.