⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apcswrite.html

📁 关于ARM汇编的非常好的教程
💻 HTML
字号:
<!doctype html public "-//W3C//DTD HTML 3.2//EN"><html><head><title>Writing an APCS program</title><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /><meta http-equiv="content-language" content="en" /><meta name="resource-type" content="document"><meta name="copyright" content="This document copyright 2001 by Richard Murray. Use for non-profit and education purposes explicitly granted."><meta name="author" content="Richard Murray"><meta name="rating" content="general"></head><!--  /assembler/apcswrite.html          --><!--                                     --><!--  (C) Copyright 2001 Richard Murray  --><!--  Designed by Richard Murray         --><!--  rmurray@heyrick.co.uk              --><!--                                     --><body bgcolor="#f0f0f0" text="#000000" link="#0022dd" vlink="#002288"><table border = "0" width="100%">  <tr>    <td align=center width=100>      <img src="arm3.gif" width=79 height=78 align = middle>    </td>    <td>      <h1 align="center"><font color="#800080">Writing an APCS program</font></h1>    </td>    <td align=center width=100>      <img src="arm3.gif" width=79 height=78 align = middle>    </td></table><p>&nbsp;<p>The <b>APCS</b>, or ARM Procedure Call Standard, provides a mechanism for writing tightlydefined routines in assembler. This may seem possibly wasteful when you consider the case ofwriting your own project entirely in assembler. However, modern applications tend to be of ahybrid fashion - the base written in a high level language, with speed-critical parts written inassembler. Then, APCS comes into its own.<p>&nbsp;<p>&nbsp;<p>In a DDE application, several directories are used:<ul>  <li> <code>h</code><br>       For header files  <li> <code>o</code><br>       For object files</ul>As <code>c</code> is used for C code, it stands to reason that <code>s</code> is used forassembler.<br>Lost?<br>Me too. I suspect 's' means source, from the days when real programmers shunned high levellanguages.<br>Whatever the reason, by convention the assembler code goes in a subdirectory called'<code>s</code>'.<p>&nbsp;<p>&nbsp;<p><h2>Registers</h2>Registers R0 to R3 are destructible. All the rest (save R14 (lr)) <i>must</i> be properlypreserved, if they are in any way altered by your code.<p>APCS defines the registers using different names to our usual R0 to R14. With the power of theassembler preprocessor, you can define R0 etc, but it is just as well to learn the APCS namesin case you are modifying code written by others.<center><table>  <tr bgcolor="#cccccc" align="center">    <td colspan = 3>Register names</td>  </tr>  <tr bgcolor="#dddddd">    <td><code>Reg #&nbsp;</code></td>    <td><code>APCS&nbsp;&nbsp;</code></td>    <td>Meaning</td>  <tr>    <td><code>R0</code></td>    <td><code>a1</code></td>    <td>Working registers</td>  </tr>  <tr>    <td><code>R1</code></td>    <td><code>a2</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R2</code></td>    <td><code>a3</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R3</code></td>    <td><code>a4</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R4</code></td>    <td><code>v1</code></td>    <td>Must be preserved</td>  </tr>  <tr>    <td><code>R5</code></td>    <td><code>v2</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R6</code></td>    <td><code>v3</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R7</code></td>    <td><code>v4</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R8</code></td>    <td><code>v5</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R9</code></td>    <td><code>v6</code></td>    <td align = center>&quot;</td>  </tr>  <tr>    <td><code>R10</code></td>    <td><code>sl</code></td>    <td>Stack Limit</td>  </tr>  <tr>    <td><code>R11</code></td>    <td><code>fp</code></td>    <td>Frame Pointer</td>  </tr>  <tr>    <td><code>R12</code></td>    <td><code>ip</code></td>    <td>&nbsp;</td>  </tr>  <tr>    <td><code>R13</code></td>    <td><code>sp</code></td>    <td>Stack Pointer</td>  </tr>  <tr>    <td><code>R14</code></td>    <td><code>lr</code></td>    <td>Link Register</td>  </tr>  <tr>    <td><code>R15</code></td>    <td><code>pc</code></td>    <td>Program Counter</td>  </tr></table></center><p>&nbsp;<p>These names are not defined by standard in Acorn's older <i>objasm</i>, though other assemblers(such as Nick Roberts' <i>ASM</i>, and the later (32 bit compatible) objasm) should define themfor you.<br>To define a register name in <i>objasm</i>, you use the <code>RN</code> directive, at the verystart of your program:<pre>a1     RN      0a2     RN      1a3     RN      2    ...etc...r13    RN      13sp     RN      13r14    RN      14lr     RN      r14pc     RN      15</pre>That example shows us two important things:<ol>  <li> That registers can be multiply defined - you can have <i>both</i> 'r13' and 'sp'.  <li> That registers can be defined from previously defined registers - 'lr' was defined from       the setting of 'r14'.<br>       (this is correct for <i>objasm</i>, other assemblers may not do this)</ol>Other assemblers may differ, like using a command such as &quot;BINDREG&quot;, refer to theinstructions for your particular example.<p>You can set up a header file, if you don't want to do all of this in every module you write.Then, for <i>objasm</i>, you simply:<pre>        GET    h.regnames</pre>For <i>ASM</i>, you would use the INCLUDE directive. Other assemblers may vary.<p>&nbsp;<p>&nbsp;<p><h2>Areas</h2>The next thing that you must do is to define your area. This may be CODE or DATA, and canoptionally be READONLY.<br>Other areas exist, but are outside the scope of this document.<br>For our purposes, we shall be writing a program or function, so our area will be a READONLY CODEarea.<p>We define this with:<pre>        AREA   |main|, CODE, READONLY</pre>This sets up an area called &quot;main&quot;. The area name must be enclosed in vertical bars,and it may be any valid identifier.<p>If we were linking our code with C, then we would call the area &quot;|C$$code|&quot;. This isdescribed in mode detail in <a href="exa6.html">example 6</a>. You cannot call a function&quot;main&quot; when interworking with C, as by convention the initial function of a C programis main(). Likewise, you cannot call your function the same as an existing one.<p>&nbsp;<p>&nbsp;<p><h2>Entry point</h2>For a stand-alone program, your next directive would be:<pre>        ENTRY</pre>to tell the assembler that this is where your program wishes to be entered. You can only have oneentry point per program.<p>When interworking with a high level language, you do not have an entry point. Instead, you havea collection of routines that are exported. Refer to <a href="exa6.html">example 6</a> for moreinformation.<br>Please note, there is quite a lot of stuff that should be set up for a stand-alone assemblerprogram, such as reading command line parameters and stack management. It gets even hairier ifyou wish to write a multitasking application entirely in assembler. Therefore, it is recommendedthat you write the basis of your program in C, and use assembler for the parts that require thespeed benefit. However, <a href="exa5.html">example 5</a> will describe a simple utility writtenentirely in assembler.<p>&nbsp;<p>&nbsp;<p><h2>Code</h2>Your code follows.<p>Now is the time to explain why the previous examples were indented eight spaces, except for theregister definitions.<p>In assembler code, there is a very simple syntax. Things on the left are counted as identifiers,while things that are indented are either instructions or directives.<br>Any line beginning with a semicolon is a comment, and a semicolon in a line of code means thatthe rest of the line is a comment.<br>You do <i>not</i> start labels with a period.Unlike BASIC, a colon does <i>not</i> start a new instruction. You can only have one instructionper line.<br>For example:<pre>r0 RN  0        AREA |main|, CODE, READONLY        ENTRY        ADR    r0, title        SWI    &02         ; OS_Write0        SWI    &10         ; OS_GetEnv        SWI    &02         ; OS_Write0        SWI    &03         ; OS_NewLine        SWI    &11         ; OS_Exittitle        =      "This program was called with:", 10, 13, "   ", 0        ALIGN        END</pre>When run, the program outputs a short title, followed by the command line that started theprogram. For example:<table width="100%"><tr bgcolor="#000000"><td><pre><font color = "#ffffff">TaskWindow Server v0.01*catDir. IDEFS::Willow.$.Coding.Projects.Assembler.apcstest Option 00 (Off) CSD  IDEFS::Willow.$.Coding.Projects.Assembler.apcstestLib. IDEFS::Buffy.$.libraryURD  IDEFS::Stephanie.$o            D/      s            D/     test         WR/*test -this -is a -testThis program was called with:   test -this -is a -test*</font></pre></td></tr></table><p>&nbsp;<p>&nbsp;<p><h2>But... that doesn't work!</h2>If you are not using <i>objasm</i>, then chances are it won't work correctly. Each assembleravailable does the basic instruction set, and also some of the BASIC commands, such as ALIGN andDCD. However, specifics and directives are pretty much up to the author of the assembler.<br>As an example, many of the assemblers will do SWI name expansion, where <code>SWI"OS_Exit"</code> will read the SWI name and calculate the SWI number for you; and ARMmaker willgo as far as to allow you to specify output types (ABSOLUTE, MODULE, AOF, etc) which is veryuseful if you don't have a linker.<p>You may also like to <a href="apcsasm.html">refer to my opinions on various assemblers</a>.<p>&nbsp;<p>&nbsp;<p><h2>The examples</h2>The examples have been written for <i>objasm</i>.<p><dl>  <dt> <a href="exa5.html">Example 5</a>:  <dd> A simple example written entirely in assembler.</dl><dl>  <dt> <a href="exa6.html">Example 6</a>:  <dd> An example of combining assembler and C.</dl><p>&nbsp;<p>&nbsp;<p><h2>More...</h2>A full explanation of APCS and assemblers is out of the scope of this guide. Assuming that youare familiar with assembler, the instructions for <i>ASM</i> and <i>ARMmaker</i> are bothinteresting reads. These two documents should provide you with sufficient information to obtaingood results from your assembler, whichever you choose, and help you write productive code.<br>However, for complete instructions (should your require them), you would need to read the PRMsand the Acorn Assembler documentation.<p>&nbsp;<p>&nbsp;<p><h2>And finally...</h2>You will (by the time you've read the details for example 6), realise that I am overstressingthe following point:<br><i>Don't recode everything in assembler because you can.</i><br>Modern compilers aren't stupid. The Norcroft v4.00 compiler, apparently, doesn't generatetotally optimised code [source: lots of arguments on comp.sys.acorn.programmer over the years]but it does perform some optimisations. And, instruction for instruction, a compiler canprobabaly out-optimise many of you. I, for one, wouldn't want to take on a compiler against mycode.<p>But don't be discouraged. Assembler has its uses. Here are some examples:<ul>  <li> A simple SWI wrapper, to remove the overheads of calling _kernel_swi() or similar.<br>       DeskLib 2.30 took a simple WIMP command - <code>Wimp_ProcessKey</code> and implemented it       in only four lines of assembler:<br><pre>MOV     ip, lrSWI     SWI_Wimp_ProcessKey + XOS_BitMOVVC   a1, #0MOVS    pc, ip ; <font color="red">(not 32-bit friendly)</font></pre>       <br>&nbsp;<br>  <li> Access to protected memory areas. One example is the podule area, which cannot be       accessed from user mode code.       <br>&nbsp;<br>  <li> And those good old processor intensive functions, like playing with memory or pixels or       anything with large amounts of bit shifting involved, or stuff that just doesn't compile       well.<br>       An interesting challenge would be to ask your compiler to generate a source listing       rather than a compiled object file (for Norcroft C, use the <code>-S</code> flag). Load       this file into your favourite editor, and read it. Can it be optimised? Is it overly       peculiar (warning: compiler code can sometimes defy logic - trust it, it (usually!) knows       what it is doing!).<br>       This is also a good way to kickstart your own assembler code. If it is slow(ish), and       doesn't call too many library functions, that you can knock up a 'working model' in C or       Pascal (both Norcroft compilers will output ARM assembly code with the -S flag) and then       you have a functional base to improve upon.</ul>I'm sure you can think of more examples that might benefit from being coded in assembler.<p>Please be sure to read '<a href = "opinion_04.html">Don't be over zealous</a>'.<hr size = "3"><a href="index.html#08">Return to assembler index</a><hr size = "3"><address>Copyright &copy; 2001 Richard Murray</address></body></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -