Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Derived from Inferno utils/6l/obj.c and utils/6l/span.c | 1 // Derived from Inferno utils/6l/obj.c and utils/6l/span.c |
2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c | 2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c |
3 // http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c | 3 // http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c |
4 // | 4 // |
5 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. | 5 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
6 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) | 6 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
7 // Portions Copyright © 1997-1999 Vita Nuova Limited | 7 // Portions Copyright © 1997-1999 Vita Nuova Limited |
8 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuov a.com) | 8 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuov a.com) |
9 // Portions Copyright © 2004,2006 Bruce Ellis | 9 // Portions Copyright © 2004,2006 Bruce Ellis |
10 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) | 10 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
(...skipping 999 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1010 if(thechar == '5') | 1010 if(thechar == '5') |
1011 return 0; | 1011 return 0; |
1012 return RegSize; | 1012 return RegSize; |
1013 } | 1013 } |
1014 | 1014 |
1015 void | 1015 void |
1016 dostkcheck(void) | 1016 dostkcheck(void) |
1017 { | 1017 { |
1018 Chain ch; | 1018 Chain ch; |
1019 LSym *s; | 1019 LSym *s; |
1020 » | 1020 |
1021 morestack = linklookup(ctxt, "runtime.morestack", 0); | 1021 morestack = linklookup(ctxt, "runtime.morestack", 0); |
1022 newstack = linklookup(ctxt, "runtime.newstack", 0); | 1022 newstack = linklookup(ctxt, "runtime.newstack", 0); |
1023 | 1023 |
1024 // TODO | |
1025 // First the nosplits on their own. | 1024 // First the nosplits on their own. |
1026 for(s = ctxt->textp; s != nil; s = s->next) { | 1025 for(s = ctxt->textp; s != nil; s = s->next) { |
1027 » » if(s->text == nil || s->text->link == nil || (ctxt->arch->textfl ag(s->text) & NOSPLIT) == 0) | 1026 » » if(s->nosplit == 0) |
1028 continue; | 1027 continue; |
1029 ctxt->cursym = s; | 1028 ctxt->cursym = s; |
1030 ch.up = nil; | 1029 ch.up = nil; |
1031 ch.sym = s; | 1030 ch.sym = s; |
1032 ch.limit = StackLimit - callsize(); | 1031 ch.limit = StackLimit - callsize(); |
1033 stkcheck(&ch, 0); | 1032 stkcheck(&ch, 0); |
1034 s->stkcheck = 1; | 1033 s->stkcheck = 1; |
iant
2014/04/16 21:29:09
I don't think you need to set the stkcheck field h
rsc
2014/04/16 22:59:16
Done.
| |
1035 } | 1034 } |
1036 ········ | 1035 ········ |
1037 // Check calling contexts. | 1036 // Check calling contexts. |
1038 // Some nosplits get called a little further down, | 1037 // Some nosplits get called a little further down, |
1039 // like newproc and deferproc. We could hard-code | 1038 // like newproc and deferproc. We could hard-code |
1040 // that knowledge but it's more robust to look at | 1039 // that knowledge but it's more robust to look at |
1041 // the actual call sites. | 1040 // the actual call sites. |
1042 for(s = ctxt->textp; s != nil; s = s->next) { | 1041 for(s = ctxt->textp; s != nil; s = s->next) { |
1043 » » if(s->text == nil || s->text->link == nil || (ctxt->arch->textfl ag(s->text) & NOSPLIT) != 0) | 1042 » » if(s->nosplit != 0) |
1044 continue; | 1043 continue; |
1045 ctxt->cursym = s; | 1044 ctxt->cursym = s; |
1046 ch.up = nil; | 1045 ch.up = nil; |
1047 ch.sym = s; | 1046 ch.sym = s; |
1048 ch.limit = StackLimit - callsize(); | 1047 ch.limit = StackLimit - callsize(); |
1049 stkcheck(&ch, 0); | 1048 stkcheck(&ch, 0); |
1050 } | 1049 } |
1051 } | 1050 } |
1052 | 1051 |
1053 static int | 1052 static int |
1054 stkcheck(Chain *up, int depth) | 1053 stkcheck(Chain *up, int depth) |
1055 { | 1054 { |
1056 Chain ch, ch1; | 1055 Chain ch, ch1; |
1057 Prog *p; | |
1058 LSym *s; | 1056 LSym *s; |
1059 » int limit, prolog; | 1057 » int limit, prolog, i, end; |
1058 » Reloc *r; | |
1059 » Pciter pcsp; | |
1060 ········ | 1060 ········ |
1061 limit = up->limit; | 1061 limit = up->limit; |
1062 s = up->sym; | 1062 s = up->sym; |
1063 p = s->text; | |
1064 ········ | 1063 ········ |
1065 » // Small optimization: don't repeat work at top. | 1064 » // Don't duplicate work: only need to consider each |
1066 » if(s->stkcheck && limit == StackLimit-callsize()) | 1065 » // function at top of safe zone once. |
1067 » » return 0; | 1066 » if(limit == StackLimit-callsize()) { |
1067 » » if(s->stkcheck) | |
1068 » » » return 0; | |
1069 » » s->stkcheck = 1; | |
1070 » } | |
1068 ········ | 1071 ········ |
1069 if(depth > 100) { | 1072 if(depth > 100) { |
1070 diag("nosplit stack check too deep"); | 1073 diag("nosplit stack check too deep"); |
1071 stkbroke(up, 0); | 1074 stkbroke(up, 0); |
1072 return -1; | 1075 return -1; |
1073 } | 1076 } |
1074 | 1077 » |
iant
2014/04/16 21:29:09
Trailing whitespace?
rsc
2014/04/16 22:59:16
Done, but everywhere in the file (sorry).
| |
1075 » if(p == nil || p->link == nil) { | 1078 » if(s->external || s->pcln == nil) { |
1076 // external function. | 1079 // external function. |
1077 // should never be called directly. | 1080 // should never be called directly. |
1078 // only diagnose the direct caller. | 1081 // only diagnose the direct caller. |
1079 if(depth == 1 && s->type != SXREF) | 1082 if(depth == 1 && s->type != SXREF) |
1080 diag("call to external function %s", s->name); | 1083 diag("call to external function %s", s->name); |
1081 return -1; | 1084 return -1; |
1082 } | 1085 } |
1083 | 1086 |
1084 if(limit < 0) { | 1087 if(limit < 0) { |
1085 stkbroke(up, limit); | 1088 stkbroke(up, limit); |
1086 return -1; | 1089 return -1; |
1087 } | 1090 } |
1088 | 1091 |
1089 // morestack looks like it calls functions, | 1092 // morestack looks like it calls functions, |
1090 // but it switches the stack pointer first. | 1093 // but it switches the stack pointer first. |
1091 if(s == morestack) | 1094 if(s == morestack) |
1092 return 0; | 1095 return 0; |
1093 | 1096 |
1094 ch.up = up; | 1097 ch.up = up; |
1095 » prolog = (ctxt->arch->textflag(s->text) & NOSPLIT) == 0; | 1098 » prolog = !s->nosplit; |
iant
2014/04/16 21:29:09
Argh, negating a flag expressed as a negative.
rsc
2014/04/16 22:59:16
I know, but NOSPLIT is the name of the assembler d
| |
1096 » for(p = s->text; p != P; p = p->link) { | 1099 » pciterinit(&pcsp, &s->pcln->pcsp); |
1097 » » limit -= p->spadj; | 1100 |
1098 » » if(prolog && p->spadj != 0) { | 1101 » // walk relocs, advancing spadj table at the same time |
1099 » » » // The first stack adjustment in a function with a | 1102 » r = nil; |
1100 » » » // split-checking prologue marks the end of the | 1103 » for(i = 0; i <= s->nr; i++) { |
1101 » » » // prologue. Assuming the split check is correct, | 1104 » » if(i == s->nr) |
1102 » » » // after the adjustment there should still be at least | 1105 » » » end = s->size; |
1103 » » » // StackLimit bytes available below the stack pointer. | 1106 » » else { |
1104 » » » // If this is not the top call in the chain, no need | 1107 » » » r = &s->r[i]; |
1105 » » » // to duplicate effort, so just stop. | 1108 » » » if(r->type != R_CALL && r->type != R_CALLIND) |
1106 » » » if(depth > 0) | 1109 » » » » continue; |
1107 » » » » return 0; | 1110 » » » end = r->off; |
1108 » » » prolog = 0; | |
1109 » » » limit = StackLimit; | |
1110 } | 1111 } |
1111 » » if(limit < 0) { | 1112 » » while(!pcsp.done && pcsp.pc < end) { |
1112 » » » stkbroke(up, limit); | 1113 » » » if(prolog && pcsp.value > 0) { |
1113 » » » return -1; | 1114 » » » » // The first stack adjustment in a function with a |
1115 » » » » // split-checking prologue marks the end of the | |
1116 » » » » // prologue. Assuming the split check is correc t, | |
1117 » » » » // after the adjustment there should still be at least | |
1118 » » » » // StackLimit bytes available below the stack po inter. | |
1119 » » » » // If this is not the top call in the chain, no need | |
1120 » » » » // to duplicate effort, so just stop. | |
1121 » » » » if(depth > 0) | |
1122 » » » » » return 0; | |
1123 » » » » prolog = 0; | |
1124 » » » » limit = StackLimit + pcsp.value; | |
1125 » » » } | |
1126 » » » if(limit - pcsp.value < 0) { | |
1127 » » » » stkbroke(up, limit - pcsp.value); | |
1128 » » » » return -1; | |
1129 » » » } | |
1130 » » » if(end < pcsp.nextpc) | |
iant
2014/04/16 21:29:09
Why check this both here and at the top of the loo
rsc
2014/04/16 22:59:16
It made sense at the time (yesterday morning). Not
rsc
2014/04/17 00:28:01
This code is tricky because it needs to iterate ov
| |
1131 » » » » break; | |
1132 » » » pciternext(&pcsp); | |
1114 } | 1133 } |
1115 » » if(ctxt->arch->iscall(p)) { | 1134 » » if(i == s->nr) |
1116 » » » limit -= callsize(); | 1135 » » » break; |
1117 » » » ch.limit = limit; | 1136 |
1118 » » » if(p->to.type == D_BRANCH) { | 1137 » » ch.limit = limit - pcsp.value - callsize(); |
1119 » » » » // Direct call. | 1138 » » if(r->type == R_CALL) { |
1120 » » » » ch.sym = p->to.sym; | 1139 » » » // Direct call. |
1121 » » » » if(stkcheck(&ch, depth+1) < 0) | 1140 » » » ch.sym = r->sym; |
1122 » » » » » return -1; | 1141 » » » if(stkcheck(&ch, depth+1) < 0) |
1123 » » » } else { | 1142 » » » » return -1; |
1124 » » » » // Indirect call. Assume it is a splitting func tion, | 1143 » » » if(prolog && s->locals == 0 && strstr(r->sym->name, "mor estack")) { |
1125 » » » » // so we have to make sure it can call morestack . | 1144 » » » » prolog = 0; |
1126 » » » » limit -= callsize(); | 1145 » » » » limit = StackLimit; |
1127 » » » » ch.sym = nil; | |
1128 » » » » ch1.limit = limit; | |
1129 » » » » ch1.up = &ch; | |
1130 » » » » ch1.sym = morestack; | |
1131 » » » » if(stkcheck(&ch1, depth+2) < 0) | |
1132 » » » » » return -1; | |
1133 » » » » limit += callsize(); | |
1134 } | 1146 } |
1135 » » » limit += callsize(); | 1147 » » } else { |
1148 » » » // Indirect call. Assume it is a splitting function, | |
1149 » » » // so we have to make sure it can call morestack. | |
1150 » » » ch.sym = nil; | |
1151 » » » ch1.limit = ch.limit - callsize(); // for morestack in c alled prologue | |
1152 » » » ch1.up = &ch; | |
1153 » » » ch1.sym = morestack; | |
1154 » » » if(stkcheck(&ch1, depth+2) < 0) | |
iant
2014/04/16 21:29:09
Because the code checks explicitly for morestack a
rsc
2014/04/16 22:59:16
Yes, to get a nice diagnostic that tells you that
| |
1155 » » » » return -1; | |
1136 } | 1156 } |
1137 ················ | |
1138 } | 1157 } |
1158 | |
1139 return 0; | 1159 return 0; |
1140 } | 1160 } |
1141 | 1161 |
1142 static void | 1162 static void |
1143 stkbroke(Chain *ch, int limit) | 1163 stkbroke(Chain *ch, int limit) |
1144 { | 1164 { |
1145 diag("nosplit stack overflow"); | 1165 diag("nosplit stack overflow"); |
1146 stkprint(ch, limit); | 1166 stkprint(ch, limit); |
1147 } | 1167 } |
1148 | 1168 |
1149 static void | 1169 static void |
1150 stkprint(Chain *ch, int limit) | 1170 stkprint(Chain *ch, int limit) |
1151 { | 1171 { |
1152 char *name; | 1172 char *name; |
1153 | 1173 |
1154 if(ch->sym) | 1174 if(ch->sym) |
1155 name = ch->sym->name; | 1175 name = ch->sym->name; |
1156 else | 1176 else |
1157 name = "function pointer"; | 1177 name = "function pointer"; |
1158 | 1178 |
1159 if(ch->up == nil) { | 1179 if(ch->up == nil) { |
1160 // top of chain. ch->sym != nil. | 1180 // top of chain. ch->sym != nil. |
1161 » » if(ctxt->arch->textflag(ch->sym->text) & NOSPLIT) | 1181 » » if(ch->sym->nosplit) |
1162 print("\t%d\tassumed on entry to %s\n", ch->limit, name) ; | 1182 print("\t%d\tassumed on entry to %s\n", ch->limit, name) ; |
1163 else | 1183 else |
1164 print("\t%d\tguaranteed after split check in %s\n", ch-> limit, name); | 1184 print("\t%d\tguaranteed after split check in %s\n", ch-> limit, name); |
1165 } else { | 1185 } else { |
1166 stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); | 1186 stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); |
1167 if(!HasLinkRegister) | 1187 if(!HasLinkRegister) |
1168 print("\t%d\ton entry to %s\n", ch->limit, name); | 1188 print("\t%d\ton entry to %s\n", ch->limit, name); |
1169 } | 1189 } |
1170 if(ch->limit != limit) | 1190 if(ch->limit != limit) |
1171 print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit ); | 1191 print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit ); |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1484 vseprint(buf, buf+sizeof(buf), fmt, arg); | 1504 vseprint(buf, buf+sizeof(buf), fmt, arg); |
1485 va_end(arg); | 1505 va_end(arg); |
1486 print("%s%s%s\n", tn, sep, buf); | 1506 print("%s%s%s\n", tn, sep, buf); |
1487 | 1507 |
1488 nerrors++; | 1508 nerrors++; |
1489 if(nerrors > 20) { | 1509 if(nerrors > 20) { |
1490 print("too many errors\n"); | 1510 print("too many errors\n"); |
1491 errorexit(); | 1511 errorexit(); |
1492 } | 1512 } |
1493 } | 1513 } |
OLD | NEW |