2015-10-16 2 views
0

Я начал изучать язык ассемблера и сразу же наткнулся на передачу аргументов. Каждое учебное пособие, которое я видел в Интернете (пример: http://www.delorie.com/djgpp/doc/ug/asm/calling.html), объясняет аргументы, передаваемые функциям, как их подталкивание к стеку. Однако, когда я начал экспериментировать, совершенно ясно, что это не так. Для простой функцииПередача аргументов функции ASM

int foo(int a, int b) { 
    return a + b; 
} 

генерируется После ASM (составлен на AMD64 с НКУ):

movl %edi, -4(%rbp) 
    movl %esi, -8(%rbp) 
    movl -8(%rbp), %eax 
    movl -4(%rbp), %edx 
    leal (%rdx,%rax), %eax 

совершенно ясно, аргументы передаются в EDI и ESI регистров. Поскольку я добавляю больше аргументов функции, я вижу больше регистров, и только после того, как я достиг 6 аргументов, я начинаю видеть значения, фактически прочитанные из стека. Тем не менее, регистры EDI/ESI в googling не дают мне объяснений их особой роли в передаче аргументов. Что мне здесь не хватает?

ответ

0

Передача аргументов в регистрах выполняется быстрее и не использует дополнительной памяти стека по сравнению с их нажатием на стек. Это функция оптимизации. По соглашению, компилятор может поместить первые пару аргументов в регистры, в зависимости от того, сколько регистров доступно в архитектуре ЦП. Компиляторы C++ всегда будут помещать «этот» аргумент в регистр при вызове функций объекта.

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

Каждый компилятор опубликовал свои соглашения о вызовах. Это то, что вам сообщают модификаторы «__cdecl» и «__stdcall» в объявлениях функций.

См. Также Microsoft calling conventions, и Wikipedia описание.

+0

Не помогло, извините. Вы повторили то, что я уже понял. Реальным является то, что я могу легко называть что-то, скомпилированное с одним компилятором C из компилируемого с другим. И __stdcall - это нечто из мира MSFT, очень далекого от меня. Должно быть что-то, что позволяет компиляторам использовать это соглашение о вызове, и это должно быть своего рода стандартом. – SergeyA

+0

Существуют стандарты, а не только один унифицирующий. – TeasingDart

+0

Хорошо, ваши последние изменения прояснили ситуацию. Это System V AMD64 ABI, как описано в Wiki. Благодарю. – SergeyA

1

Похоже, вы ждете традиционных 32-разрядные соглашения о вызовах в 64-битном программы .

Если вы скомпилируете и создаете приложение в виде 32-разрядного приложения, то скомпилированный код для foo() должен работать так, как вы ожидаете, с аргументами, вставленными в стек.

Для 64-разрядных приложений соглашения о вызовах (или ABI) различаются, и большинство аргументов передаются в регистре по мере того, как вы видите. См. Этот другой вопрос здесь: Where is the X86-64 ABI documented? для более подробной информации.

Когда была введена архитектура AMD64, было создано несколько причин для создания нового ABI, одним из которых было хорошее использование большего количества регистров процессора. Передача некоторых аргументов в регистрах вместо их нажатия в стеке более эффективна.

+0

Извините, слишком поздно - у меня уже есть один выше. Я полностью понимаю идею вызова конвенции, только все материалы, которые я нашел в Интернете, почему-то не упоминали AMD64 ABI. – SergeyA

Смежные вопросы