ld: add NOPTRBSS for large, pointer-free uninitialized data
cc: add #pragma textflag to set it
runtime: mark mheap to go into noptr-bss.
        remove special case in garbage collector

Remove the ARM from.flag field created by CL 5687044.
The DUPOK flag was already in p->reg, so keep using that.

Otherwise test/nilptr.go creates a very large binary.
Should fix the arm build.
Diagnosed by minux.ma; replacement for CL 5690044.

R=golang-dev, minux.ma, r
CC=golang-dev
https://golang.org/cl/5686060
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index ab7e522..4bef021 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -491,7 +491,6 @@
 
 	Bputc(&obuf, a->type);
 	Bputc(&obuf, a->reg);
-	Bputc(&obuf, 0); // flag
 	Bputc(&obuf, s);
 	Bputc(&obuf, a->name);
 	switch(a->type) {
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index 124a971..7268f9a 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -564,10 +564,9 @@
 
 	bp[0] = a->type;
 	bp[1] = a->reg;
-	bp[2] = 0; // flag
-	bp[3] = s;
-	bp[4] = a->name;
-	bp += 5;
+	bp[2] = s;
+	bp[3] = a->name;
+	bp += 4;
 	switch(a->type) {
 	default:
 		diag(Z, "unknown type %d in zaddr", a->type);
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index 4de8908..dea406e 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -139,7 +139,9 @@
 			continue;
 		if(s->type == types[TENUM])
 			continue;
+		textflag = s->dataflag;
 		gpseudo(AGLOBL, s, nodconst(s->type->width));
+		textflag = 0;
 	}
 	nextpc();
 	p->as = AEND;
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 99b2607..7dbf3be 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -27,7 +27,6 @@
 	uchar	reg;
 	char pun;
 	uchar	etype;
-	char	flag;
 };
 #define	A	((Addr*)0)
 
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index 1e0e96f..b562ba8 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -93,7 +93,6 @@
 	default:
 		Bputc(b, a->type);
 		Bputc(b, a->reg);
-		Bputc(b, a->flag);
 		Bputc(b, s);
 		Bputc(b, a->name);
 	}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 387ebad..86f05fb 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -254,9 +254,9 @@
 	p->to.type = D_CONST;
 	p->to.offset = width;
 	if(nam->readonly)
-		p->from.flag = RODATA;
+		p->reg = RODATA;
 	if(nam->type != T && !haspointers(nam->type))
-		p->from.flag |= NOPTR;
+		p->reg |= NOPTR;
 }
 
 void
@@ -273,7 +273,7 @@
 	p->to.offset = width;
 	if(dupok)
 		p->reg = DUPOK;
-	p->from.flag |= RODATA;
+	p->reg |= RODATA;
 }
 
 int
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 4a4bfe1..5edc270 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -75,6 +75,7 @@
 	ElfStrPlt,
 	ElfStrNoteNetbsdIdent,
 	ElfStrNoPtrData,
+	ElfStrNoPtrBss,
 	NElfStr
 };
 
@@ -168,6 +169,7 @@
 	elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+	elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
 	if(HEADTYPE == Hnetbsd)
 		elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
 	addstring(shstrtab, ".rodata");
@@ -1847,12 +1849,14 @@
 			case STYPE:
 			case SSTRING:
 			case SGOSTRING:
+			case SNOPTRDATA:
 				if(!s->reachable)
 					continue;
 				put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
 				continue;
 
 			case SBSS:
+			case SNOPTRBSS:
 				if(!s->reachable)
 					continue;
 				put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index 4abb6f2..b1a48de 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -76,7 +76,6 @@
 	uchar	index; // not used on arm, required by ld/go.c
 	char	reg;
 	char	name;
-	char	flag;
 	int32	offset2; // argsize
 	char	class;
 	Sym*	gotype;
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 316a9a0..eb07851 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -301,7 +301,6 @@
 
 	a->type = Bgetc(f);
 	a->reg = Bgetc(f);
-	a->flag = Bgetc(f);
 	c = Bgetc(f);
 	if(c < 0 || c > NSYM){
 		print("sym out of range: %d\n", c);
@@ -541,7 +540,7 @@
 			s->type = SBSS;
 			s->value = 0;
 		}
-		if(s->type != SBSS && s->type != SNOPTRDATA && !s->dupok) {
+		if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
 			diag("redefinition: %s\n%P", s->name, p);
 			s->type = SBSS;
 			s->value = 0;
@@ -550,10 +549,14 @@
 			s->size = p->to.offset;
 		if(p->reg & DUPOK)
 			s->dupok = 1;
-		if(p->from.flag & RODATA)
+		if(p->reg & RODATA)
 			s->type = SRODATA;
-		else if(p->from.flag & NOPTR)
-			s->type = SNOPTRDATA;
+		else if(p->reg & NOPTR) {
+			if(s->np > 0)
+				s->type = SNOPTRDATA;
+			else
+				s->type = SNOPTRBSS;
+		}
 		break;
 
 	case ADATA:
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index 2e1232a..13e1848 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -421,6 +421,8 @@
 	case SDATA:
 	case SBSS:
 	case SCONST:
+	case SNOPTRDATA:
+	case SNOPTRBSS:
 		break;
 	}
 	return v;
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index dd232f0..2cb8c15 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -158,7 +158,9 @@
 			continue;
 		if(s->type == types[TENUM])
 			continue;
+		textflag = s->dataflag;
 		gpseudo(AGLOBL, s, nodconst(s->type->width));
+		textflag = 0;
 	}
 	nextpc();
 	p->as = AEND;
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index b64a6dab..d5954ea 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -96,6 +96,7 @@
 	ElfStrGnuVersionR,
 	ElfStrNoteNetbsdIdent,
 	ElfStrNoPtrData,
+	ElfStrNoPtrBss,
 	NElfStr
 };
 
@@ -573,6 +574,7 @@
 	elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+	elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
 	if(HEADTYPE == Hnetbsd)
 		elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
 	addstring(shstrtab, ".elfdata");
@@ -1169,6 +1171,7 @@
 		case SCONST:
 		case SRODATA:
 		case SDATA:
+		case SNOPTRDATA:
 		case SELFROSECT:
 		case SMACHOGOT:
 		case STYPE:
@@ -1181,6 +1184,7 @@
 			continue;
 
 		case SBSS:
+		case SNOPTRBSS:
 			if(!s->reachable)
 				continue;
 			put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 19f85f0..f441f33 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -555,7 +555,7 @@
 			s->type = SBSS;
 			s->size = 0;
 		}
-		if(s->type != SBSS && s->type != SNOPTRDATA && !s->dupok) {
+		if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
 			diag("%s: redefinition: %s in %s",
 				pn, s->name, TNAME);
 			s->type = SBSS;
@@ -567,8 +567,12 @@
 			s->dupok = 1;
 		if(p->from.scale & RODATA)
 			s->type = SRODATA;
-		else if(p->from.scale & NOPTR)
-			s->type = SNOPTRDATA;
+		else if(p->from.scale & NOPTR) {
+			if(s->np > 0)
+				s->type = SNOPTRDATA;
+			else
+				s->type = SNOPTRBSS;
+		}
 		goto loop;
 
 	case ADATA:
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index 65c551e..3a08da7 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -146,7 +146,9 @@
 			continue;
 		if(s->type == types[TENUM])
 			continue;
+		textflag = s->dataflag;
 		gpseudo(AGLOBL, s, nodconst(s->type->width));
+		textflag = 0;
 	}
 	nextpc();
 	p->as = AEND;
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 27881d8..2b8137f 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -92,6 +92,7 @@
 	ElfStrGnuVersionR,
 	ElfStrNoteNetbsdIdent,
 	ElfStrNoPtrData,
+	ElfStrNoPtrBss,
 	NElfStr
 };
 
@@ -530,6 +531,7 @@
 	elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+	elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
 	if(HEADTYPE == Hnetbsd)
 		elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
 	addstring(shstrtab, ".elfdata");
@@ -1256,12 +1258,14 @@
 			case SSTRING:
 			case SGOSTRING:
 			case SWINDOWS:
+			case SNOPTRDATA:
 				if(!s->reachable)
 					continue;
 				put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
 				continue;
 
 			case SBSS:
+			case SNOPTRBSS:
 				if(!s->reachable)
 					continue;
 				put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 566494e..f463236 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -122,6 +122,7 @@
 	uchar	sym;
 	uchar	aused;
 	uchar	sig;
+	uchar	dataflag;
 };
 #define	S	((Sym*)0)
 
@@ -524,6 +525,7 @@
 EXTERN	int	packflg;
 EXTERN	int	fproundflg;
 EXTERN	int	textflag;
+EXTERN	int	dataflag;
 EXTERN	int	ncontin;
 EXTERN	int	canreach;
 EXTERN	int	warnreach;
@@ -766,6 +768,7 @@
 void	pragvararg(void);
 void	pragpack(void);
 void	pragfpround(void);
+void	pragdataflag(void);
 void	pragtextflag(void);
 void	pragincomplete(void);
 void	pragdynimport(void);
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index d624bf2..a3ed977 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -120,6 +120,10 @@
 		(*f)(c, t, s);
 		if(s->class == CLOCAL)
 			s = mkstatic(s);
+		if(dataflag) {
+			s->dataflag = dataflag;
+			dataflag = 0;
+		}
 		firstbit = 0;
 		n->sym = s;
 		n->type = s->type;
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 084aa04..c579e20 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -567,13 +567,7 @@
 void
 pragtextflag(void)
 {
-	Sym *s;
-
-	textflag = 0;
-	s = getsym();
-	textflag = 7;
-	if(s)
-		textflag = atoi(s->name+1);
+	textflag = getnsn();
 	while(getnsc() != '\n')
 		;
 	if(debug['f'])
@@ -581,6 +575,16 @@
 }
 
 void
+pragdataflag(void)
+{
+	dataflag = getnsn();
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		print("%4d: dataflag %d\n", lineno, dataflag);
+}
+
+void
 pragincomplete(void)
 {
 	Sym *s;
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index f4cc19c..d339cf9 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -75,6 +75,13 @@
 }
 
 void
+pragdataflag(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
 pragprofile(void)
 {
 	while(getnsc() != '\n')
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
index ed66361..874e82d 100644
--- a/src/cmd/cc/macbody
+++ b/src/cmd/cc/macbody
@@ -731,6 +731,10 @@
 		pragtextflag();
 		return;
 	}
+	if(s && strcmp(s->name, "dataflag") == 0) {
+		pragdataflag();
+		return;
+	}
 	if(s && strcmp(s->name, "varargck") == 0) {
 		pragvararg();
 		return;
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index e5e1db6..5ed8568 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -806,8 +806,12 @@
 	}
 
 	for(s = datap; s != nil; s = s->next) {
-		if(s->np > 0 && s->type == SBSS)
-			s->type = SDATA;
+		if(s->np > 0) {
+			if(s->type == SBSS)
+				s->type = SDATA;
+			if(s->type == SNOPTRBSS)
+				s->type = SNOPTRDATA;
+		}
 		if(s->np > s->size)
 			diag("%s: initialize bounds (%lld < %d)",
 				s->name, (vlong)s->size, s->np);
@@ -935,11 +939,24 @@
 		datsize += t;
 	}
 
-	/* bss */
+	/* bss, then pointer-free bss */
+	noptr = nil;
 	sect = addsection(&segdata, ".bss", 06);
 	sect->vaddr = datsize;
-	for(; s != nil; s = s->next) {
-		if(s->type != SBSS) {
+	for(; ; s = s->next) {
+		if((s == nil || s->type >= SNOPTRBSS) && noptr == nil) {
+			// finish bss, start noptrbss
+			datsize = rnd(datsize, 8);
+			sect->len = datsize - sect->vaddr;
+			sect = addsection(&segdata, ".noptrbss", 06);
+			sect->vaddr = datsize;
+			noptr = sect;
+		}
+		if(s == nil) {
+			sect->len = datsize - sect->vaddr;
+			break;
+		}
+		if(s->type > SNOPTRBSS) {
 			cursym = s;
 			diag("unexpected symbol type %d", s->type);
 		}
@@ -961,7 +978,6 @@
 		s->value = datsize;
 		datsize += t;
 	}
-	sect->len = datsize - sect->vaddr;
 }
 
 // assign addresses to text
@@ -1004,7 +1020,7 @@
 void
 address(void)
 {
-	Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr;
+	Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
 	Sym *sym, *sub;
 	uvlong va;
 
@@ -1031,6 +1047,8 @@
 		segdata.fileoff = segtext.fileoff + segtext.filelen;
 	data = nil;
 	noptr = nil;
+	bss = nil;
+	noptrbss = nil;
 	for(s=segdata.sect; s != nil; s=s->next) {
 		s->vaddr = va;
 		va += s->len;
@@ -1040,8 +1058,12 @@
 			data = s;
 		if(strcmp(s->name, ".noptrdata") == 0)
 			noptr = s;
+		if(strcmp(s->name, ".bss") == 0)
+			bss = s;
+		if(strcmp(s->name, ".noptrbss") == 0)
+			noptrbss = s;
 	}
-	segdata.filelen -= data->next->len; // deduct .bss
+	segdata.filelen -= bss->len + noptrbss->len; // deduct .bss
 
 	text = segtext.sect;
 	rodata = text->next;
@@ -1068,7 +1090,11 @@
 	xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
 	xdefine("noptrdata", SBSS, noptr->vaddr);
 	xdefine("enoptrdata", SBSS, noptr->vaddr + noptr->len);
+	xdefine("bss", SBSS, bss->vaddr);
+	xdefine("ebss", SBSS, bss->vaddr + bss->len);
 	xdefine("data", SBSS, data->vaddr);
 	xdefine("edata", SBSS, data->vaddr + data->len);
+	xdefine("noptrbss", SBSS, noptrbss->vaddr);
+	xdefine("enoptrbss", SBSS, noptrbss->vaddr + noptrbss->len);
 	xdefine("end", SBSS, segdata.vaddr + segdata.len);
 }
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index a66a571..f5881b5 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -49,6 +49,7 @@
 	SMACHOGOT,
 	SWINDOWS,
 	SBSS,
+	SNOPTRBSS,
 
 	SXREF,
 	SMACHODYNSTR,
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index d893599..6d76e9e 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -334,6 +334,10 @@
 	xdefine("enoptrdata", SBSS, 0);
 	xdefine("data", SBSS, 0);
 	xdefine("edata", SBSS, 0);
+	xdefine("bss", SBSS, 0);
+	xdefine("ebss", SBSS, 0);
+	xdefine("noptrbss", SBSS, 0);
+	xdefine("enoptrbss", SBSS, 0);
 	xdefine("end", SBSS, 0);
 	xdefine("epclntab", SRODATA, 0);
 	xdefine("esymtab", SRODATA, 0);
diff --git a/src/libmach/5obj.c b/src/libmach/5obj.c
index a5827f5..e539362 100644
--- a/src/libmach/5obj.c
+++ b/src/libmach/5obj.c
@@ -112,7 +112,7 @@
 	long off;
 
 	a.type = Bgetc(bp);	/* a.type */
-	skip(bp,2);		/* reg, flag */
+	skip(bp,1);		/* reg */
 	a.sym = Bgetc(bp);	/* sym index */
 	a.name = Bgetc(bp);	/* sym type */
 	switch(a.type){
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index c9f1d67..932e3d9 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -14,7 +14,9 @@
 #include "defs_GOOS_GOARCH.h"
 #include "type.h"
 
+#pragma dataflag 16 /* mark mheap as 'no pointers', hiding from garbage collector */
 MHeap runtime·mheap;
+
 extern MStats mstats;	// defined in extern.go
 
 extern volatile int32 runtime·MemProfileRate;
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 8efa7af..fd1babf 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -85,7 +85,7 @@
 
 extern byte data[];
 extern byte etext[];
-extern byte end[];
+extern byte ebss[];
 
 static G *fing;
 static FinBlock *finq; // list of finalizers that are to be executed
@@ -630,10 +630,7 @@
 	FinBlock *fb;
 
 	// mark data+bss.
-	// skip runtime·mheap itself, which has no interesting pointers
-	// and is mostly zeroed and would not otherwise be paged in.
-	scan(data, (byte*)&runtime·mheap - data);
-	scan((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1));
+	scan(data, ebss - data);
 
 	// mark stacks
 	for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {