📄 using_in-line_assembly_calling_external_assembly_from_c.html
字号:
<p> The underscore in front of the function name <em><strong>addition</strong></em> is necessary because the compiler prefixes an underscore to user defined procedures when it is generating the object file, this process is known as mangling.</p><p> The way in which data is passed into and returned from the subroutine depends on the data types and the number of arguments. In this case the first argument to the function is passed in through register R0, the second argument is passed in through register R1, and the result is returned through register R0. To observer how data will be passed into your function you can view the assembly code that the compiler generates by calling compiler with the <strong>-S</strong> switch as follows:</p><pre class="code">bash$ bin-elf-gcc -S <C code source file(s)></pre><p>This will generate the assembly code for your program and write it to a file with the <em>*.s</em> extension. Examination of this file will reveal how parameters will be passed into your function.</p><p> When including assembly code from a separate file you must insure that any special registers that are altered by your assembly code are first saved and then restored. If this is not done unwanted side effects may be introduced into your program. Also, when compiling your program you must pass the name of the assembly code file to the compiler along with any other files your program is dependent on. For example a program with the C code source file <code>myprog.c</code> and the assembly code file <code>myprog.s</code> may be compiled with the following command:</p><pre class="code">bash$ bin-elf-gcc -o myprog myprog.c myprog.s</pre><p>Some more complex examples of assembly subroutines will now be given.</p><p>Consider a function which adds five numbers together with the C definition:</p><pre class="code">extern int addition(int,int,int,int,int);</pre><p>Examination of the assembly code generated when calling such a function shows that the first three parameters are stored in registers R0, R1, and R2. The last two parameters are pushed onto the stack. The assembly code used to add these five numbers together might look something like the following:</p><pre class="code">.global _addition;_addition:LINK 0; [--sp] = R7; R3 =[FP +8]; R7 =[FP +12]; R0 =R0 +R1 ; R0 =R0 +R2 ; R0 =R0 +R3 ; R0 =R0 +R7 ; R7 = [sp++]; UNLINK;RTS;</pre><p>First, we will be retrieving variables from the stack so <em><strong>LINK</strong></em> is called to allocate frame space on the stack. Next, because we are modifying registers other than R0-R3, we must save these registers by pushing them onto the stack. In this case we only need to push R7. Next the last two parameters are retrieved from the stack by moving up from our frame pointer. The first 8 byte addition to the frame pointer moves us past the saved prior frame pointer and the saved RETS to the second last parameter. Another 4 bytes past this gives us the last parameter. These parameters are saved to registers R3 and R7 then added to the parameters saved in registers R0-R2. The result is returned through register R0. Register R7 is restored from the stack then our stack frame is de-allocated using the <em><strong>UNLINK</strong></em> instruction. <em><strong> RTS</strong></em> returns us from the subroutine. The positions of the frame pointer and the stack pointer as well as the contents of the stack are illustrated below, each cell represents 4 bytes:</p><p><a href="media/assembly1.png" class="media" target="_blank" title="assembly1.png"><img src="media/assembly1.png" class="media" alt="" /></a></p><p>Now consider a function where the values of two parameters need to be swapped. The parameters are passed in by address instead of by value. The C definition of the function is as follows:</p><pre class="code">void swap(int* v1, int* v2){ int tmp; tmp = *v1; *v1 = *v2; *v2 = tmp; return;}</pre><p>The assembly version is as follows</p><pre class="code">.global _swap;_swap:LINK 0; P2 = R0; P1 = R1; R1 = [P2]; R0 = [P1]; [P2] = R0; [P1] = R1; UNLINK;RTS;</pre></div><!-- SECTION [1-10846] --><h3><a name="bfin-elf-gcc_parameter_passing_convention_runtime_model" id="bfin-elf-gcc_parameter_passing_convention_runtime_model">bfin-elf-gcc Parameter Passing Convention/Runtime Model</a></h3><div class="level3"><p> Firstly test your code using the -S option for *gcc*. This will allow you to see some example code.</p><p>If you want to write an assember function, start with a dummy C function and inspect the assembly output.</p><p>The once the <acronym title="Application Programming Interface">API</acronym> has been confirmed with a dummy function move on to the real assembly code.</p><p>A called function may clobber all registers, except RETS, R4-R7, P3-P5, FP and SP. It may also modify the first 12 bytes in the caller’s stack frame which is used as an argument area for the first three arguments (which are passed in R0...R3 but may be placed on the stack by the called function).</p><p>A called function may assume that all L registers are zero when entered, and must ensure that they remain zero when it returns.</p><pre class="code">.global _stacktest;_stacktest: [--sp] = (r7:6) LINK 0; R7 = R0; R6 = R1 + R2; R0 = R1 + R7 + R6; UNLINK; (r7:6) = [sp++];RTS;</pre></div><!-- SECTION [10847-] --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -