В обычном соглашении о вызовах MIPS, аргументы после 4-го уже будут храниться в стеке вызовов, помещенном там вашим вызывающим абонентом.
Стандартное соглашение о вызовах оставляет заполнение перед аргументами стека, где вы можете хранить аргументы регистров для создания непрерывного массива всех аргументов. Этот PDF-файл содержит диаграмму , а также см. вызов функции MIPS с более чем четырьмя аргументами
Обычно это называется «теневым пространством» в Windows x86-64. Но поскольку MIPS jal
ничего не сохраняет в памяти (в отличие от x86, который помещает адрес возврата в стек, MIPS помещает адрес возврата в $lr
), даже если соглашение о вызовах не включает это теневое пространство в функцию все еще можно сначала настроить SP, а затем сохранить аргументы регистров, смежные с аргументами стека. Таким образом, единственное преимущество, которое я могу видеть, это дать крошечным функциям дополнительное пространство для нуля без необходимости настройки указателя стека. Это менее полезно, чем в x86-64, где без него невозможно легко создать массив аргументов.
Или вы можете очистить первые 3 итерации суммы, которые обрабатывают $a1
.. $a3
(опять-таки, предполагая стандартное соглашение о вызовах MIPS с первыми 4 аргументами в регистрах, $a0
- int n
).
Затем переберите аргументы стека, если вы еще не достигли n
.
Вы можете написать функцию C и посмотреть на оптимизированный вывод компилятора, например, что
#include
int sumargs(int n, ...) {
va_list args;
va_start(args, n);
int sum=0;
for (int i=0 ; i
va_start
и va_arg
не являются реальными функциями; они расширятся до некоторого встроенного кода. va_start(args,n)
сбрасывает регистры передачи аргументов после n
в теневое пространство (смежное с аргументами стека, если есть).
MIPS gcc, к сожалению, не поддерживает опцию -mregnames
для использования имен, таких как $ a0 и $ t0, но Google нашел хорошую таблицу с именем регистра < -> number
Вывод MIPS asm из проводника компилятора Godbolt
# gcc5.4 -O3 -fno-delayed-branch
sumargs(int, ...):
# on entry: SP points 16 bytes below the first non-register arg, if there is one.
addiu $sp,$sp,-16 # reserve another 16 bytes
addiu $3,$sp,20 # create a pointer to the base of this array
sw $5,20($sp) # dump $a1..$a3 into the shadow space
sw $6,24($sp)
sw $7,28($sp)
sw $3,8($sp) # spill the pointer into scratch space for some reason?
blez $4,$L4 # check if the loop should run 0 times.
nop # branch-delay slot. (MARS can simulate a MIPS without delayed branches, so I told gcc to fill the slots with nops)
move $5,[111] # i=0
move $2,[111] # $v0 = sum = 0
$L3: # do {
lw $6,0($3)
addiu $5,$5,1 # i++
addu $2,$2,$6 # sum += *arg_pointer
addiu $3,$3,4 # arg_pointer++ (4 bytes)
bne $4,$5,$L3 # } while(i != n)
nop # fill the branch-delay slot
$L2:
addiu $sp,$sp,16
j $31 # return (with sum in $v0)
nop
$L4:
move $2,[111] # return 0
b $L2
nop
Зацикливание на do {}while(--n)
было бы более эффективным. Это пропущенная оптимизация, что gcc не делает этого при компиляции цикла for.
Некоторые доступные методы:
Поочередно Вы могли записать свой собственный закон использования и yacc (или их семья - гибкий провод и бизон) использование общедоступной спецификации закона и yacc грамматики.
Возможно, GNU project cflow http: / /www.gnu.org/software/cflow/?
Возможно излишество, но существует полный ANSI C синтаксический анализатор, записанный с Повышением. Дух: http://spirit.sourceforge.net/repository/applications/c.zip
Возможно, Вы сможете смоделировать его для удовлетворения потребностям.
Я не знаю, предлагает ли это библиотеку, но взгляните на CTAGS.
Если это - плоскость C, lex
и yacc
Ваши друзья, но необходимо взять препроцессор учетной записи C - исходные файлы с нерасширенными макросами обычно, не выполняют синтаксис C, таким образом, синтаксический анализатор, записанный с грамматикой K&R в памяти, скорее всего, перестанет работать.
Если Вы решаете проанализировать вывод препроцессора, подготовлены, что Ваш синтаксический анализатор перестанет работать из-за "расширений" Вашего конкретного компилятора, потому что вероятные стандартные заголовки библиотеки используют их. По крайней мере, это случай с GCC.
Я имел это с GCC и наконец решил достигнуть своей цели с помощью другого подхода. Если просто необходимо изменить имена для переменных, регулярные выражения сделают прекрасный, и нет никакой потребности создать полный синтаксический анализатор, по моему скромному мнению. Если Ваша цель состоит в том, чтобы только собрать данные, окончательный источник данных является отладочной информацией. Существуют способы вытащить отладочную информацию из двоичного файла - для исполняемых файлов ELF с КАРЛИКОМ существует libdwarf для земли Windows (COFF?) должно быть что-то также. Вероятно, можно использовать некоторые существующие инструменты для получения отладочной информации о двоичном файле - снова, я ничего не знаю о Windows, необходимо заняться расследованиями.
Недавно я прочитал о системе на основе win32, которая просматривала отладочную информацию в файлах DLL COFF: http://www.drizzle.com/~scottb/gdc/fubi-paper.htm
Анализировать C намного сложнее, чем кажется, когда вы принимаете учтите разные диалекты, директивы препроцессора, необходимость информации о типе при парсинге и т. д. Люди, которые говорят вам "просто используйте lex и yacc", имеют явно не производил синтаксический анализатор C.
Инструмент, который может это сделать, - это наш интерфейсный модуль C
Он решает все вышеперечисленные проблемы.
По завершении он имеет полную таблицу символов с возможностью навигации. со всеми идентификаторами и соответствующей информацией о типе. При этом перечисление глобальных и локальных переменных было бы тривиальным делом.
Я архитектор семантических дизайнов.