Have delocate process lines by pulling.

In order to better handle BSS sections, rather than having a single loop
over the lines and state flags, pull lines as needed. This means that
subfunctions can process sections of the input.

Also, stop bothering to move the init_array to the end, it's already put
into its own section.

Change-Id: I0e62930c65d29baecb39ba0d8bbc21f2da3bde56
Reviewed-on: https://boringssl-review.googlesource.com/15204
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/delocate.go b/crypto/fipsmodule/delocate.go
index 2215f25..6d7be13 100644
--- a/crypto/fipsmodule/delocate.go
+++ b/crypto/fipsmodule/delocate.go
@@ -132,6 +132,25 @@
 	symbol string
 }
 
+type lineSource struct {
+	lines     []string
+	lineNo    int
+}
+
+func (ls *lineSource) Next() (string, bool) {
+	if ls.lineNo == len(ls.lines) {
+		return "", false
+	}
+
+	ret := ls.lines[ls.lineNo]
+	ls.lineNo++
+	return ret, true
+}
+
+func (ls *lineSource) Unread() {
+	ls.lineNo--
+}
+
 // transform performs a number of transformations on the given assembly code.
 // See FIPS.md in the current directory for an overview.
 func transform(lines []string, symbols map[string]bool) (ret []string) {
@@ -145,12 +164,6 @@
 	// referenced and thus needs to be emitted outside the module.
 	ia32capAddrNeeded := false
 
-	// extractedText contains lines that have been extracted from the
-	// assembly and need to be moved outside of the module. (This is used
-	// for the .init_array section that specifies constructors.)
-	var extractedText []string
-	extractingText := false
-
 	// bssAccessorsNeeded contains the names of BSS symbols for which
 	// accessor functions need to be emitted outside of the module.
 	var bssAccessorsNeeded []string
@@ -159,7 +172,14 @@
 	// offsets in the thread-local storage.
 	threadLocalOffsets := make(map[string]threadLocalOffsetFunc)
 
-	for lineNo, line := range lines {
+	source := &lineSource{lines: lines}
+
+	for {
+		line, ok := source.Next()
+		if !ok {
+			break
+		}
+
 		// References to OPENSSL_ia32cap_P via the GOT result from C
 		// code. The OPENSSL_ia32cap_addr symbol, generated by this
 		// script, is just like a GOT entry, but at a known offset.
@@ -260,13 +280,6 @@
 			ret = append(ret, line)
 			continue
 
-		case ".file":
-			// Do not reorder .file directives. These define
-			// numbered files which are referenced by other debug
-			// directives which may not be reordered.
-			ret = append(ret, line)
-			continue
-
 		case ".comm":
 			p := strings.Split(parts[1], ",")
 			name := p[0]
@@ -274,8 +287,6 @@
 			ret = append(ret, line)
 
 		case ".section":
-			extractingText = false
-
 			p := strings.Split(parts[1], ",")
 			section := p[0]
 
@@ -293,30 +304,13 @@
 
 			switch section {
 			case ".data", ".data.rel.ro.local":
-				panic(fmt.Sprintf("bad section %q on line %d", parts[1], lineNo+1))
-
-			case ".init_array":
-				// init_array contains function pointers to
-				// constructor functions. Since these must be
-				// relocated, this section is moved to the end
-				// of the file.
-				extractedText = append(extractedText, line)
-				extractingText = true
+				panic(fmt.Sprintf("bad section %q on line %d", parts[1], source.lineNo))
 
 			default:
 				ret = append(ret, line)
 			}
 
-		case ".text":
-			extractingText = false
-			fallthrough
-
 		default:
-			if extractingText {
-				extractedText = append(extractedText, line)
-				continue
-			}
-
 			if symbol, ok := isSymbolDef(line); ok {
 				if isGlobal := symbols[symbol]; isGlobal {
 					ret = append(ret, localTargetName(symbol)+":")
@@ -385,8 +379,6 @@
 		ret = append(ret, ".byte 0x"+strconv.FormatUint(uint64(b), 16))
 	}
 
-	ret = append(ret, extractedText...)
-
 	return ret
 }