2015-12-09 11 views
1

В настоящее время я работаю с реализацией процессора RISC-V. Мне нужно запустить частично ручной код сборки. (Наконец, будет динамическая инъекция кода.) Для этого я должен понять основы вызовов функций в сборке RISC-V.Сборка RISC-V - компоновка стека - вызов функции

Я нашел эту тему очень полезно: confusion about function call stack

Но я до сих пор борюсь с макетом стека для вызова функции. Пожалуйста, рассмотрите следующий c-код:

void some_func(int a, int b, int* c){ 
    int cnt = a; 
    for(;cnt > 0;cnt--){ 
     *c += b; 
    } 
} 

void main(){ 
    int a = 5; 
    int b = 6; 
    int c = 0; 

    some_func(a,b,&c); 
} 

Эта программа реализует базовое умножение на последовательность дополнений. Выведенный код сборки (riscv64 неизвестный эльф-GCC -nostartfiles mul.c -o мул & & riscv64 неизвестный эльф-objdump -D мул) выглядит следующим образом:

0000000000010000 <some_func>: 
    10000: fd010113   addi sp,sp,-48 
    10004: 02813423   sd s0,40(sp) 
    10008: 03010413   addi s0,sp,48 
    1000c: fca42e23   sw a0,-36(s0) 
    10010: fcb42c23   sw a1,-40(s0) 
    10014: fcc43823   sd a2,-48(s0) 
    10018: fdc42783   lw a5,-36(s0) 
    1001c: fef42623   sw a5,-20(s0) 
    10020: 0280006f   j 10048 <some_func+0x48> 
    10024: fd043783   ld a5,-48(s0) 
    10028: 0007a703   lw a4,0(a5) 
    1002c: fd842783   lw a5,-40(s0) 
    10030: 00f7073b   addw a4,a4,a5 
    10034: fd043783   ld a5,-48(s0) 
    10038: 00e7a023   sw a4,0(a5) 
    1003c: fec42783   lw a5,-20(s0) 
    10040: fff7879b   addiw a5,a5,-1 
    10044: fef42623   sw a5,-20(s0) 
    10048: fec42783   lw a5,-20(s0) 
    1004c: fcf04ce3   bgtz a5,10024 <some_func+0x24> 
    10050: 00000013   nop 
    10054: 02813403   ld s0,40(sp) 
    10058: 03010113   addi sp,sp,48 
    1005c: 00008067   ret 

0000000000010060 <main>: 
    10060: fe010113   addi sp,sp,-32 
    10064: 00113c23   sd ra,24(sp) 
    10068: 00813823   sd s0,16(sp) 
    1006c: 02010413   addi s0,sp,32 
    10070: 00500793   li a5,5 
    10074: fef42623   sw a5,-20(s0) 
    10078: 00600793   li a5,6 
    1007c: fef42423   sw a5,-24(s0) 
    10080: fe042223   sw zero,-28(s0) 
    10084: fe440793   addi a5,s0,-28 
    10088: 00078613   mv a2,a5 
    1008c: fe842583   lw a1,-24(s0) 
    10090: fec42503   lw a0,-20(s0) 
    10094: f6dff0ef   jal 10000 <some_func> 
    10098: 00000013   nop 
    1009c: 01813083   ld ra,24(sp) 
    100a0: 01013403   ld s0,16(sp) 
    100a4: 02010113   addi sp,sp,32 
    100a8: 00008067   ret 

важные шаги, которые необходимо осветление являются: (some_func (интермедиат, Int, Int))

10060: fe010113   addi sp,sp,-32 
    10064: 00113c23   sd ra,24(sp) 
    10068: 00813823   sd s0,16(sp) 
    1006c: 02010413   addi s0,sp,32 

и: (основной())

10000: fd010113   addi sp,sp,-48 
    10004: 02813423   sd s0,40(sp) 
    10008: 03010413   addi s0,sp,48 

Из моего понимания: stackpointer перемещается, чтобы освободить место для RETU rn-адрес и параметры. (Основной может быть здесь особый случай.) Как переданные аргументы обрабатываются, когда они находятся в стеке? Как они получены? В общем, методология ясна для меня, но как бы я скомпоновал этот сегмент для того, чтобы работать.

Что касается соответствующей теме, стек должен выглядеть примерно так

| ???       | 
| params for some_func() <???> | 
| ra of some_func()    | 
| locals of main()  <int c> | 
| locals of main()  <int b> | 
| locals of main()  <int a> | 
| params for main()  <None> | 

Но это в значительной степени это. Может ли кто-нибудь указать, как это устроено, и как эти два списка (вызов функции) связаны между собой?

ответ

1

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

важные шаги, которые нуждаются в разъяснении, являются:

10060: fe010113   addi sp,sp,-32 # allocate space 
    10064: 00113c23   sd ra,24(sp)  # save $ra 
    10068: 00813823   sd s0,16(sp)  # save $s0 
    1006c: 02010413   addi s0,sp,32 # set up $s0 as frame pointer 
+0

Ваш комментарий точно указал, что я пропал без вести. Таким образом, регистр $ s0 (указатель кадра (страница 93 RISC-V ISA) будет использоваться относительной адресацией для восстановления параметров после вызова функции. (Я попытался использовать относительную адресацию на основе $ sp, что заставило симулятор crash.) Когда вы ввели новый контекст функции, я могу использовать $ s0 (указатель кадра) для восстановления всех необходимых параметров. Прошу прощения за то, что вы несколько неспецифичны, но я, очевидно, не получил концепцию полностью.) – Kennerd

+0

адресация относительно '$ sp' действительно, если вы разбили симулятор, я думаю, это означает, что вы перепутали смещения. Он должен работать. – Jester