@@ -3,6 +3,7 @@ package compiler
33import (
44 _ "embed"
55 "fmt"
6+ "strconv"
67 "strings"
78
89 log "github.com/sirupsen/logrus"
@@ -254,15 +255,17 @@ var instructions = map[string]func(*OutputWriter, AssemblyCommand){
254255 "bexti" : bexti ,
255256}
256257var directives = map [string ]func (* OutputWriter , []string ){
257- ".asciz" : asciz ,
258- ".string" : asciz ,
259- ".base64" : base64data ,
260- ".quad" : quad ,
261- ".word" : word ,
262- ".byte" : byte_ ,
263- ".half" : half ,
264- ".zero" : zero ,
265- ".set" : set ,
258+ ".asciz" : asciz ,
259+ ".string" : asciz ,
260+ ".base64" : base64data ,
261+ ".quad" : quad ,
262+ ".word" : word ,
263+ ".byte" : byte_ ,
264+ ".half" : half ,
265+ ".zero" : zero ,
266+ ".align" : align ,
267+ ".p2align" : align ,
268+ ".set" : set ,
266269}
267270
268271/* main */
@@ -286,19 +289,150 @@ func CompileInstruction(writer *OutputWriter, command AssemblyCommand) {
286289 label (writer , command )
287290 }
288291}
292+ func normalizeSection (name string ) string {
293+ name = strings .Split (name , "," )[0 ]
294+ name = strings .Trim (name , "\" " )
295+ if strings .HasPrefix (name , ".rodata" ) {
296+ return ".rodata"
297+ }
298+ if strings .HasPrefix (name , ".sdata" ) {
299+ return ".sdata"
300+ }
301+ if strings .HasPrefix (name , ".data" ) {
302+ return ".data"
303+ }
304+ if strings .HasPrefix (name , ".sbss" ) {
305+ return ".sbss"
306+ }
307+ if strings .HasPrefix (name , ".bss" ) {
308+ return ".bss"
309+ }
310+ if strings .HasPrefix (name , ".text" ) {
311+ return ".text"
312+ }
313+ return ".rodata"
314+ }
315+
289316func BeforeCompilation (writer * OutputWriter ) {
317+ /* Pass 1: Collect all labels into MemoryMap */
318+ tempMaxPC := 1
319+ var pendingLabels []string
320+
321+ sectionPointers := map [string ]int32 {
322+ ".rodata" : 1024 ,
323+ ".data" : 1024 * 1024 , // 1MB
324+ ".sdata" : 2 * 1024 * 1024 , // 2MB
325+ ".bss" : 3 * 1024 * 1024 , // 3MB
326+ ".sbss" : 4 * 1024 * 1024 , // 4MB
327+ ".text" : 5 * 1024 * 1024 , // 5MB
328+ }
329+ currentSection := ".text"
330+
331+ // Provide dummy allocations for common newlib/C externs
332+ writer .MemoryMap ["_impure_ptr" ] = 16
333+ writer .MemoryMap ["_ctype_" ] = 32
334+
335+ for i := range writer .Commands {
336+ if writer .Commands [i ].Type == Label {
337+ labelName := writer .Commands [i ].Name
338+ pendingLabels = append (pendingLabels , labelName )
339+ writer .MemoryMap [labelName ] = tempMaxPC // default to current MaxPC
340+ } else if writer .Commands [i ].Type == Instruction && writer .Commands [i ].Name != "" {
341+ for _ , l := range pendingLabels {
342+ writer .MemoryMap [l ] = tempMaxPC
343+ }
344+ pendingLabels = nil
345+ tempMaxPC ++
346+ } else if writer .Commands [i ].Type == Directive {
347+ attributeComponents := ReadDirective (writer .Commands [i ].Name )
348+ attributeName := attributeComponents [0 ]
290349
291- /* load directives */
350+ if attributeName == ".section" || attributeName == ".text" || attributeName == ".data" || attributeName == ".bss" || attributeName == ".sdata" || attributeName == ".sbss" {
351+ sec := attributeName
352+ if attributeName == ".section" && len (attributeComponents ) > 1 {
353+ sec = attributeComponents [1 ]
354+ }
355+ currentSection = normalizeSection (sec )
356+ continue
357+ }
358+
359+ tempMemPtr := sectionPointers [currentSection ]
360+
361+ for _ , l := range pendingLabels {
362+ writer .MemoryMap [l ] = int (tempMemPtr )
363+ }
364+ pendingLabels = nil
365+
366+ // Some directives increment MemoryDevelopmentPointer
367+ if attributeName == ".asciz" || attributeName == ".string" {
368+ data , _ := UnescapeDirectiveString (attributeComponents [1 ])
369+ tempMemPtr += int32 (len (data ) + 1 )
370+ } else if attributeName == ".word" {
371+ tempMemPtr += 4
372+ } else if attributeName == ".half" {
373+ tempMemPtr += 2
374+ } else if attributeName == ".byte" {
375+ tempMemPtr += 1
376+ } else if attributeName == ".quad" {
377+ tempMemPtr += 8
378+ } else if attributeName == ".zero" {
379+ size , _ := strconv .Atoi (attributeComponents [1 ])
380+ tempMemPtr += int32 (size )
381+ } else if attributeName == ".align" || attributeName == ".p2align" {
382+ pow , _ := strconv .Atoi (attributeComponents [1 ])
383+ alignSize := int32 (1 << pow )
384+ rem := tempMemPtr % alignSize
385+ if rem != 0 {
386+ tempMemPtr += alignSize - rem
387+ }
388+ } else if attributeName == ".set" {
389+ symName := attributeComponents [1 ]
390+ if len (attributeComponents ) >= 3 {
391+ if attributeComponents [2 ] == "." && len (attributeComponents ) >= 5 {
392+ offset , _ := strconv .Atoi (attributeComponents [4 ])
393+ if attributeComponents [3 ] == "+" {
394+ writer .MemoryMap [symName ] = int (tempMemPtr ) + offset
395+ } else if attributeComponents [3 ] == "-" {
396+ writer .MemoryMap [symName ] = int (tempMemPtr ) - offset
397+ }
398+ } else {
399+ val , err := strconv .Atoi (attributeComponents [2 ])
400+ if err == nil {
401+ writer .MemoryMap [symName ] = val
402+ } else {
403+ if existingAddr , ok := writer .MemoryMap [attributeComponents [2 ]]; ok {
404+ writer .MemoryMap [symName ] = existingAddr
405+ }
406+ }
407+ }
408+ }
409+ }
410+
411+ sectionPointers [currentSection ] = tempMemPtr
412+ }
413+ }
414+
415+ /* Pass 2: Actually process directives and write init() function */
292416 WriteIndentedString (writer , "function init(): ()\n " )
293417 writer .Depth ++
294418 WriteIndentedString (writer , "reset_registers()\n " )
295419
296- /* pre-read the code, and write directive to top */
420+ sectionPointers = map [string ]int32 {
421+ ".rodata" : 1024 ,
422+ ".data" : 1024 * 1024 ,
423+ ".sdata" : 2 * 1024 * 1024 ,
424+ ".bss" : 3 * 1024 * 1024 ,
425+ ".sbss" : 4 * 1024 * 1024 ,
426+ ".text" : 5 * 1024 * 1024 ,
427+ }
428+ currentSection = ".text"
429+ writer .MemoryDevelopmentPointer = sectionPointers [currentSection ]
430+
297431 for i := range writer .Commands {
298432 if writer .Commands [i ].Type == Label {
299433 writer .CurrentLabel = & writer .Commands [i ]
300434 writer .Commands [i ].Ignore = true
301- writer .PendingData = PendingData {} // reset so first directive under this label always saves pointer
435+ writer .PendingData = PendingData {}
302436 }
303437 if writer .Commands [i ].Type == Instruction && writer .Commands [i ].Name != "" {
304438 if writer .CurrentLabel != nil {
@@ -308,23 +442,42 @@ func BeforeCompilation(writer *OutputWriter) {
308442 if writer .Commands [i ].Type == Directive {
309443 attributeComponents := ReadDirective (writer .Commands [i ].Name )
310444 attributeName := attributeComponents [0 ]
445+
446+ if attributeName == ".section" || attributeName == ".text" || attributeName == ".data" || attributeName == ".bss" || attributeName == ".sdata" || attributeName == ".sbss" {
447+ sectionPointers [currentSection ] = writer .MemoryDevelopmentPointer
448+ sec := attributeName
449+ if attributeName == ".section" && len (attributeComponents ) > 1 {
450+ sec = attributeComponents [1 ]
451+ }
452+ currentSection = normalizeSection (sec )
453+ writer .MemoryDevelopmentPointer = sectionPointers [currentSection ]
454+ continue
455+ }
456+
311457 if _ , ok := directives [attributeName ]; ok {
312458 directives [attributeName ](writer , attributeComponents )
313459 } else if writer .Options .Comments {
314460 WriteIndentedString (writer , "-- ASM DIRECTIVE: %s\n " , writer .Commands [i ].Name )
315461 }
316462 }
317463 }
464+ sectionPointers [currentSection ] = writer .MemoryDevelopmentPointer
465+
466+ /* reset MaxPC for second pass */
467+ writer .MaxPC = 1
318468
319469 /* finish loading directives */
320470 WriteIndentedString (writer , "PC = %d\n " , FindLabelAddress (writer , writer .Options .MainSymbol ))
321- WriteIndentedString (writer , "r3 = (buffer.len(memory) + %d) / 2 -- start at the center after static data\n " , writer . MemoryDevelopmentPointer )
471+ WriteIndentedString (writer , "r3 = %d -- start at the center after static data\n " , 8 * 1024 * 1024 )
322472 WriteIndentedString (writer , "if r3 >= buffer.len(memory) then error(\" Not enough memory\" ) end\n " )
323473 writer .Depth --
324474 WriteIndentedString (writer , "end\n " )
325475
326- /* start code */
476+ log .Infof ("Section ends: rodata=%d, data=%d, sdata=%d, bss=%d, sbss=%d, text=%d" ,
477+ sectionPointers [".rodata" ], sectionPointers [".data" ], sectionPointers [".sdata" ],
478+ sectionPointers [".bss" ], sectionPointers [".sbss" ], sectionPointers [".text" ])
327479}
480+
328481func AfterCompilation (writer * OutputWriter ) []byte {
329482 AddEnd (writer ) // end the current label, if active
330483
0 commit comments