2011-01-09 3 views
5

Есть ли способ заставить gcc передать параметры функции в стеке?Заставить gcc передать параметры в стеке

Я не хочу использовать регистры для передачи параметров.

Обновление: I'am с помощью рычага-GCC от CodeSourcery

+3

Почему параметры в регистрах плохо? –

+0

Неплохо. Я просто хочу, чтобы параметры передавались таким образом, потому что I'am // emulating // процедура создания потока (и распределения стека). – cojocar

+0

Какая архитектура/ABI? – ephemient

ответ

0

В соответствии с: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf

Первые четыре регистра r0-r3 (а1-а4) используются для передачи значений аргументов в a подпрограмма и вернуть результат значение от функции. Они также могут использовать для хранения промежуточных значений в рамках обычной (но, вообще говоря, только между вызовами подпрограмм).

В ARM нет других соглашений о вызовах, но по умолчанию, о которых я знаю. И вот почему:

  1. Зачем вам это нужно? Ваша функция не будет вызываться в скомпилированной форме другими функциями, создавая беспорядок совместимости.
  2. Ваши вызовы системных функций, которые соответствуют ABI, не будут работать, если только компилятор не смог провести различие между соглашениями о вызовах. Теперь я знаю, что в прошлом существуют разные соглашения о вызовах для x86-32, но обратите внимание, как x64 проще (AMD64 против Microsoft). Почему при проектировании ARM calling convention вы бы разрешили так много разных соглашений? Это создает беспорядок совместимости.
+1

Да, вы правы. Это необычная вещь, особенно из-за причин, о которых вы упомянули. Идея состоит в том, что определенная функция была основной частью потока - в пользовательской среде (ОС). Пользовательская ОС будет вызывать аргумент потока в стеке. Чтобы уважать ABI, существует два метода обхода: поместите аргумент в r0 или объявите * thread_func (uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3, void * param) *. Благодаря! – cojocar

+1

Почему бы не поместить их в регистры? Вам нужно будет сохранять регистры по потокам, но вам все равно - представьте, если вы переключили потоки во время выполнения, а значения регистра старой функции остались на месте ... если бы ОС это сделали, это было бы очень грязно. –

+0

Нить создается из пользовательского пространства, и нет API (syscall) для установки значения регистра для вновь созданного потока. – cojocar

1

Вы можете попробовать обернуть параметры в структуре; например, если ваша функция int calc_my_sum(int x, int y) {return x+y;} вы можете изменить его следующим образом (некрасиво):

struct my_x_y { 
    int x, y; 
    my_x_y(): x(0), y(0) {} // a non-trivial constructor to make the type non-POD 
}; 

int calc_my_sum(my_x_y x_and_y) { 
    // passing non-POD object by value forces to use the stack 
    return x_and_y.x + x_and_y.y; 
} 

В качестве альтернативы, вы можете просто добавить 4 параметра фиктивных израсходовать регистры, так и другие параметры будут использовать стек:

struct force_stack_usage { 
    int dummy0, dummy1, dummy2, dummy3; 
} 

int calc_my_sum(force_stack_usage, int x, int y) { 
    return x + y; 
} 
+0

Хороший взлом! Первое решение - только C++, я забыл упомянуть, что мне нужен C-решение. Благодарю. – cojocar

+1

Нет необходимости в причудливом конструкторе C++ для достижения того, чего вы хотите. В C-структурах просто копируются в стек. В C99 вы могли бы даже вызвать функцию с помощью 'calc_my_sum ((my_x_y) {.x = 5, .y = 7})' или обернуть такую ​​вещь в макрос без проблем. –

0

Где хранить локальную переменную зависит от того, как ее использовать. Если вам нужно получить адрес локальной переменной, локальная переменная может быть сохранена только в стеке. Поэтому, когда вы передаете свою подпрограмму указателю, этот параметр будет передан через стек.

+0

Я не уверен, что это касается вопроса или нет ... – Nanomurf