ld65-5.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD> <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.20"> <TITLE>ld65 Users Guide: Configuration files</TITLE> <LINK HREF="ld65-6.html" REL=next> <LINK HREF="ld65-4.html" REL=previous> <LINK HREF="ld65.html#toc5" REL=contents></HEAD><BODY><A HREF="ld65-6.html">Next</A><A HREF="ld65-4.html">Previous</A><A HREF="ld65.html#toc5">Contents</A><HR><H2><A NAME="config-files"></A> <A NAME="s5">5.</A> <A HREF="ld65.html#toc5">Configuration files</A></H2><P>Configuration files are used to describe the layout of the output file(s). Twomajor topics are covered in a config file: The memory layout of the targetarchitecture, and the assignment of segments to memory areas. In addition,several other attributes may be specified.</P><P>Case is ignored for keywords, that is, section or attribute names, but it is<EM>not</EM> ignored for names and strings.</P><H2><A NAME="ss5.1">5.1</A> <A HREF="ld65.html#toc5.1">Memory areas</A></H2><P>Memory areas are specified in a <CODE>MEMORY</CODE> section. Lets have a look at anexample (this one describes the usable memory layout of the C64):</P><P><BLOCKQUOTE><CODE><PRE> MEMORY { RAM1: start = $0800, size = $9800; ROM1: start = $A000, size = $2000; RAM2: start = $C000, size = $1000; ROM2: start = $E000, size = $2000; }</PRE></CODE></BLOCKQUOTE></P><P>As you can see, there are two ram areas and two rom areas. The names(before the colon) are arbitrary names that must start with a letter, withthe remaining characters being letters or digits. The names of the memoryareas are used when assigning segments. As mentioned above, case issignificant for these names.</P><P>The syntax above is used in all sections of the config file. The name(<CODE>ROM1</CODE> etc.) is said to be an identifier, the remaining tokens up to thesemicolon specify attributes for this identifier. You may use the equal signto assign values to attributes, and you may use a comma to separateattributes, you may also leave both out. But you <EM>must</EM> use a semicolon tomark the end of the attributes for one identifier. The section above may alsohave looked like this:</P><P><BLOCKQUOTE><CODE><PRE> # Start of memory section MEMORY { RAM1: start $0800 size $9800; ROM1: start $A000 size $2000; RAM2: start $C000 size $1000; ROM2: start $E000 size $2000; }</PRE></CODE></BLOCKQUOTE></P><P>There are of course more attributes for a memory section than just start andsize. Start and size are mandatory attributes, that means, each memory areadefined <EM>must</EM> have these attributes given (the linker will check that). Iwill cover other attributes later. As you may have noticed, I've used acomment in the example above. Comments start with a hash mark (`#'), theremainder of the line is ignored if this character is found.</P><H2><A NAME="ss5.2">5.2</A> <A HREF="ld65.html#toc5.2">Segments</A></H2><P>Let's assume you have written a program for your trusty old C64, and you wouldlike to run it. For testing purposes, it should run in the <CODE>RAM</CODE> area. Sowe will start to assign segments to memory sections in the <CODE>SEGMENTS</CODE>section:</P><P><BLOCKQUOTE><CODE><PRE> SEGMENTS { CODE: load = RAM1, type = ro; RODATA: load = RAM1, type = ro; DATA: load = RAM1, type = rw; BSS: load = RAM1, type = bss, define = yes; }</PRE></CODE></BLOCKQUOTE></P><P>What we are doing here is telling the linker, that all segments go into the<CODE>RAM1</CODE> memory area in the order specified in the <CODE>SEGMENTS</CODE> section. Sothe linker will first write the <CODE>CODE</CODE> segment, then the <CODE>RODATA</CODE>segment, then the <CODE>DATA</CODE> segment - but it will not write the <CODE>BSS</CODE>segment. Why? Enter the segment type: For each segment specified, you may alsospecify a segment attribute. There are five possible segment attributes:</P><P><BLOCKQUOTE><CODE><PRE> ro means readonly wprot same as ro but will be marked as write protected in the VICE label file if -Lp is given rw means read/write bss means that this is an uninitialized segment zp a zeropage segment</PRE></CODE></BLOCKQUOTE></P><P>So, because we specified that the segment with the name BSS is of type bss,the linker knows that this is uninitialized data, and will not write it to anoutput file. This is an important point: For the assembler, the <CODE>BSS</CODE>segment has no special meaning. You specify, which segments have the bssattribute when linking. This approach is much more flexible than having onefixed bss segment, and is a result of the design decision to supporting anarbitrary segment count.</P><P>If you specify "<CODE>type = bss</CODE>" for a segment, the linker will make sure thatthis segment does only contain uninitialized data (that is, zeroes), and issuea warning if this is not the case.</P><P>For a <CODE>bss</CODE> type segment to be useful, it must be cleared somehow by yourprogram (this happens usually in the startup code - for example the startupcode for cc65 generated programs takes care about that). But how does yourcode know, where the segment starts, and how big it is? The linker is able togive that information, but you must request it. This is, what we're doing withthe "<CODE>define = yes</CODE>" attribute in the <CODE>BSS</CODE> definitions. For eachsegment, where this attribute is true, the linker will export three symbols.</P><P><BLOCKQUOTE><CODE><PRE> __NAME_LOAD__ This is set to the address where the segment is loaded. __NAME_RUN__ This is set to the run address of the segment. We will cover run addresses later. __NAME_SIZE__ This is set to the segment size.</PRE></CODE></BLOCKQUOTE></P><P>Replace <CODE>NAME</CODE> by the name of the segment, in the example above, this wouldbe <CODE>BSS</CODE>. These symbols may be accessed by your code.</P><P>Now, as we've configured the linker to write the first three segments andcreate symbols for the last one, there's only one question left: Where doesthe linker put the data? It would be very convenient to have the data in afile, wouldn't it?</P><H2><A NAME="ss5.3">5.3</A> <A HREF="ld65.html#toc5.3">Output files</A></H2><P>We don't have any files specified above, and indeed, this is not needed in asimple configuration like the one above. There is an additional attribute"file" that may be specified for a memory area, that gives a file name towrite the area data into. If there is no file name given, the linker willassign the default file name. This is "a.out" or the one given with the<CODE><A HREF="ld65-2.html#option-o">-o</A></CODE> option on the command line. Since thedefault behaviour is ok for our purposes, I did not use the attribute in theexample above. Let's have a look at it now.</P><P>The "file" attribute (the keyword may also be written as "FILE" if you likethat better) takes a string enclosed in double quotes (`"') that specifies thefile, where the data is written. You may specifiy the same file several times,in that case the data for all memory areas having this file name is writteninto this file, in the order of the memory areas defined in the <CODE>MEMORY</CODE>section. Let's specify some file names in the <CODE>MEMORY</CODE> section used above:</P><P><BLOCKQUOTE><CODE><PRE> MEMORY { RAM1: start = $0800, size = $9800, file = %O; ROM1: start = $A000, size = $2000, file = "rom1.bin"; RAM2: start = $C000, size = $1000, file = %O; ROM2: start = $E000, size = $2000, file = "rom2.bin"; }</PRE></CODE></BLOCKQUOTE></P><P>The <CODE>%O</CODE> used here is a way to specify the default behaviour explicitly:<CODE>%O</CODE> is replaced by a string (including the quotes) that contains thedefault output name, that is, "a.out" or the name specified with the <CODE><A HREF="ld65-2.html#option-o">-o</A></CODE> option on the command line. Into this file, thelinker will first write any segments that go into <CODE>RAM1</CODE>, and will appendthen the segments for <CODE>RAM2</CODE>, because the memory areas are given in thisorder. So, for the RAM areas, nothing has really changed.</P><P>We've not used the ROM areas, but we will do that below, so we give the filenames here. Segments that go into <CODE>ROM1</CODE> will be written to a file named"rom1.bin", and segments that go into <CODE>ROM2</CODE> will be written to a filenamed "rom2.bin". The name given on the command line is ignored in both cases.</P><H2><A NAME="ss5.4">5.4</A> <A HREF="ld65.html#toc5.4">LOAD and RUN addresses (ROMable code)</A></H2><P>Let us look now at a more complex example. Say, you've successfully testedyour new "Super Operating System" (SOS for short) for the C64, and youwill now go and replace the ROMs by your own code. When doing that, youface a new problem: If the code runs in RAM, we need not to care aboutread/write data. But now, if the code is in ROM, we must care about it.Remember the default segments (you may of course specify your own):</P><P><BLOCKQUOTE><CODE><PRE> CODE read only code RODATA read only data DATA read/write data BSS uninitialized data, read/write</PRE></CODE></BLOCKQUOTE></P><P>Since <CODE>BSS</CODE> is not initialized, we must not care about it now, but whatabout <CODE>DATA</CODE>? <CODE>DATA</CODE> contains initialized data, that is, data that wasexplicitly assigned a value. And your program will rely on these values onstartup. Since there's no other way to remember the contents of the datasegment, than storing it into one of the ROMs, we have to put it there. Butunfortunately, ROM is not writeable, so we have to copy it into RAM beforerunning the actual code.</P><P>The linker cannot help you copying the data from ROM into RAM (this must bedone by the startup code of your program), but it has some features that willhelp you in this process.</P><P>First, you may not only specify a "<CODE>load</CODE>" attribute for a segment, butalso a "<CODE>run</CODE>" attribute. The "<CODE>load</CODE>" attribute is mandatory, and, ifyou don't specify a "<CODE>run</CODE>" attribute, the linker assumes that load areaand run area are the same. We will use this feature for our data area:</P><P><BLOCKQUOTE><CODE><PRE> SEGMENTS { CODE: load = ROM1, type = ro; RODATA: load = ROM2, type = ro; DATA: load = ROM2, run = RAM2, type = rw, define = yes; BSS: load = RAM2, type = bss, define = yes; }</PRE></CODE></BLOCKQUOTE></P><P>Let's have a closer look at this <CODE>SEGMENTS</CODE> section. We specify that the<CODE>CODE</CODE> segment goes into <CODE>ROM1</CODE> (the one at $A000). The readonly datagoes into <CODE>ROM2</CODE>. Read/write data will be loaded into <CODE>ROM2</CODE> but is runin <CODE>RAM2</CODE>. That means that all references to labels in the <CODE>DATA</CODE>segment are relocated to be in <CODE>RAM2</CODE>, but the segment is written to<CODE>ROM2</CODE>. All your startup code has to do is, to copy the data from it'slocation in <CODE>ROM2</CODE> to the final location in <CODE>RAM2</CODE>.</P><P>So, how do you know, where the data is located? This is the second point,where you get help from the linker. Remember the "<CODE>define</CODE>" attribute?Since we have set this attribute to true, the linker will define threeexternal symbols for the data segment that may be accessed from your code:</P><P><BLOCKQUOTE><CODE><PRE> __DATA_LOAD__ This is set to the address where the segment is loaded, in this case, it is an address in ROM2. __DATA_RUN__ This is set to the run address of the segment, in this case, it is an address in RAM2. __DATA_SIZE__ This is set to the segment size.</PRE></CODE></BLOCKQUOTE></P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -