@@ -449,8 +449,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
449
449
if global .IsNil () {
450
450
return errors .New ("global not found: " + globalName )
451
451
}
452
+ globalType := global .GlobalValueType ()
453
+ if globalType .TypeKind () != llvm .StructTypeKind || globalType .StructName () != "runtime._string" {
454
+ // Verify this is indeed a string. This is needed so
455
+ // that makeGlobalsModule can just create the right
456
+ // globals of string type without checking.
457
+ return fmt .Errorf ("%s: not a string" , globalName )
458
+ }
452
459
name := global .Name ()
453
- newGlobal := llvm .AddGlobal (mod , global . GlobalValueType () , name + ".tmp" )
460
+ newGlobal := llvm .AddGlobal (mod , globalType , name + ".tmp" )
454
461
global .ReplaceAllUsesWith (newGlobal )
455
462
global .EraseFromParentAsGlobal ()
456
463
newGlobal .SetName (name )
@@ -538,6 +545,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
538
545
}
539
546
}
540
547
548
+ // Insert values from -ldflags="-X ..." into the IR.
549
+ // This is a separate module, so that the "runtime._string" type
550
+ // doesn't need to match precisely. LLVM tends to rename that type
551
+ // sometimes, leading to errors. But linking in a separate module
552
+ // works fine. See:
553
+ // https://github.com/tinygo-org/tinygo/issues/4810
554
+ globalsMod := makeGlobalsModule (ctx , globalValues , machine )
555
+ llvm .LinkModules (mod , globalsMod )
556
+
541
557
// Create runtime.initAll function that calls the runtime
542
558
// initializer of each package.
543
559
llvmInitFn := mod .NamedFunction ("runtime.initAll" )
@@ -590,7 +606,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
590
606
591
607
// Run all optimization passes, which are much more effective now
592
608
// that the optimizer can see the whole program at once.
593
- err := optimizeProgram (mod , config , globalValues )
609
+ err := optimizeProgram (mod , config )
594
610
if err != nil {
595
611
return err
596
612
}
@@ -1145,7 +1161,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
1145
1161
// optimizeProgram runs a series of optimizations and transformations that are
1146
1162
// needed to convert a program to its final form. Some transformations are not
1147
1163
// optional and must be run as the compiler expects them to run.
1148
- func optimizeProgram (mod llvm.Module , config * compileopts.Config , globalValues map [ string ] map [ string ] string ) error {
1164
+ func optimizeProgram (mod llvm.Module , config * compileopts.Config ) error {
1149
1165
err := interp .Run (mod , config .Options .InterpTimeout , config .DumpSSA ())
1150
1166
if err != nil {
1151
1167
return err
@@ -1163,12 +1179,6 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues m
1163
1179
}
1164
1180
}
1165
1181
1166
- // Insert values from -ldflags="-X ..." into the IR.
1167
- err = setGlobalValues (mod , globalValues )
1168
- if err != nil {
1169
- return err
1170
- }
1171
-
1172
1182
// Run most of the whole-program optimizations (including the whole
1173
1183
// O0/O1/O2/Os/Oz optimization pipeline).
1174
1184
errs := transform .Optimize (mod , config )
@@ -1182,10 +1192,19 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues m
1182
1192
return nil
1183
1193
}
1184
1194
1185
- // setGlobalValues sets the global values from the -ldflags="-X ..." compiler
1186
- // option in the given module. An error may be returned if the global is not of
1187
- // the expected type.
1188
- func setGlobalValues (mod llvm.Module , globals map [string ]map [string ]string ) error {
1195
+ func makeGlobalsModule (ctx llvm.Context , globals map [string ]map [string ]string , machine llvm.TargetMachine ) llvm.Module {
1196
+ mod := ctx .NewModule ("cmdline-globals" )
1197
+ targetData := machine .CreateTargetData ()
1198
+ defer targetData .Dispose ()
1199
+ mod .SetDataLayout (targetData .String ())
1200
+
1201
+ stringType := ctx .StructCreateNamed ("runtime._string" )
1202
+ uintptrType := ctx .IntType (targetData .PointerSize () * 8 )
1203
+ stringType .StructSetBody ([]llvm.Type {
1204
+ llvm .PointerType (ctx .Int8Type (), 0 ),
1205
+ uintptrType ,
1206
+ }, false )
1207
+
1189
1208
var pkgPaths []string
1190
1209
for pkgPath := range globals {
1191
1210
pkgPaths = append (pkgPaths , pkgPath )
@@ -1201,24 +1220,6 @@ func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) erro
1201
1220
for _ , name := range names {
1202
1221
value := pkg [name ]
1203
1222
globalName := pkgPath + "." + name
1204
- global := mod .NamedGlobal (globalName )
1205
- if global .IsNil () || ! global .Initializer ().IsNil () {
1206
- // The global either does not exist (optimized away?) or has
1207
- // some value, in which case it has already been initialized at
1208
- // package init time.
1209
- continue
1210
- }
1211
-
1212
- // A strin is a {ptr, len} pair. We need these types to build the
1213
- // initializer.
1214
- initializerType := global .GlobalValueType ()
1215
- if initializerType .TypeKind () != llvm .StructTypeKind || initializerType .StructName () == "" {
1216
- return fmt .Errorf ("%s: not a string" , globalName )
1217
- }
1218
- elementTypes := initializerType .StructElementTypes ()
1219
- if len (elementTypes ) != 2 {
1220
- return fmt .Errorf ("%s: not a string" , globalName )
1221
- }
1222
1223
1223
1224
// Create a buffer for the string contents.
1224
1225
bufInitializer := mod .Context ().ConstString (value , false )
@@ -1229,22 +1230,20 @@ func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) erro
1229
1230
buf .SetLinkage (llvm .PrivateLinkage )
1230
1231
1231
1232
// Create the string value, which is a {ptr, len} pair.
1232
- zero := llvm .ConstInt (mod .Context ().Int32Type (), 0 , false )
1233
- ptr := llvm .ConstGEP (bufInitializer .Type (), buf , []llvm.Value {zero , zero })
1234
- if ptr .Type () != elementTypes [0 ] {
1235
- return fmt .Errorf ("%s: not a string" , globalName )
1236
- }
1237
- length := llvm .ConstInt (elementTypes [1 ], uint64 (len (value )), false )
1238
- initializer := llvm .ConstNamedStruct (initializerType , []llvm.Value {
1239
- ptr ,
1233
+ length := llvm .ConstInt (uintptrType , uint64 (len (value )), false )
1234
+ initializer := llvm .ConstNamedStruct (stringType , []llvm.Value {
1235
+ buf ,
1240
1236
length ,
1241
1237
})
1242
1238
1243
- // Set the initializer. No initializer should be set at this point.
1239
+ // Create the string global.
1240
+ global := llvm .AddGlobal (mod , stringType , globalName )
1244
1241
global .SetInitializer (initializer )
1242
+ global .SetAlignment (targetData .PrefTypeAlignment (stringType ))
1245
1243
}
1246
1244
}
1247
- return nil
1245
+
1246
+ return mod
1248
1247
}
1249
1248
1250
1249
// functionStackSizes keeps stack size information about a single function
0 commit comments