161 ]. |
233 ]. |
162 self error:'do not know how to link absolute' |
234 self error:'do not know how to link absolute' |
163 |
235 |
164 ! ! |
236 ! ! |
165 |
237 |
166 !ObjectFileLoader class methodsFor:'dynamic loading'! |
|
167 |
|
168 loadFile:aFileName library:librariesString withBindings:bindings in:aClass |
|
169 "first, load the file itself" |
|
170 |
|
171 (self loadFile:aFileName with:librariesString) ifFalse:[^ false]. |
|
172 |
|
173 "then, create stubs" |
|
174 self bindExternalFunctions:bindings in:aClass |
|
175 ! |
|
176 |
|
177 loadFile:aFileName withBindings:bindings in:aClass |
|
178 "load an object file containing external functions, and bind the functions as described |
|
179 in bindings, which is an Array of |
|
180 (selector functionName argTypes returnType) |
|
181 entries, example: |
|
182 #( |
|
183 (sel1:and: 'f1' (SmallInteger SmallInteger) nil) -> bind 'aClass sel1:and:' to: 'void f1(int, int)' |
|
184 (sel2:and: 'f2' (String SmallInteger) String) -> bind 'aClass sel2:and:' to: 'char *f2(char *, int)' |
|
185 ) |
|
186 " |
|
187 |
|
188 "first, load the file itself" |
|
189 |
|
190 (self loadFile:aFileName) ifFalse:[^ false]. |
|
191 |
|
192 "then, create stubs" |
|
193 self bindExternalFunctions:bindings in:aClass |
|
194 ! |
|
195 |
|
196 bindExternalFunctions:bindings in:aClass |
|
197 | selector functionName argTypes returnType allOk | |
|
198 |
|
199 allOk := true. |
|
200 bindings do:[:aBinding | |
|
201 selector := aBinding at:1. |
|
202 functionName := aBinding at:2. |
|
203 argTypes := aBinding at:3. |
|
204 returnType := aBinding at:4. |
|
205 (self createStubFor:selector calling:functionName args:argTypes returning:returnType in:aClass) |
|
206 isNil ifTrue:[ |
|
207 Transcript showCr:'binding of ' , functionName , ' failed.'. |
|
208 allOk := false |
|
209 ] |
|
210 ]. |
|
211 ^ allOk |
|
212 ! ! |
|
213 |
|
214 !ObjectFileLoader class methodsFor:'creating stubs'! |
|
215 |
|
216 storeGlobalAddressesOn:aStream |
|
217 |
|
218 Smalltalk allKeysDo:[:key | |
|
219 self storeGlobalAddressOf:key on:aStream |
|
220 ] |
|
221 |
|
222 "ObjectFileLoader storeGlobalAddressesOn:Transcript" |
|
223 "|f| |
|
224 f := FileStream newFileNamed:'syms.c'. |
|
225 ObjectFileLoader storeGlobalAddressesOn:f. |
|
226 f close" |
|
227 ! |
|
228 |
|
229 storeGlobalAddressOf:aSymbol on:aStream |
|
230 |globalName| |
|
231 |
|
232 globalName := aSymbol asString. |
|
233 (globalName includes:$:) ifTrue:[ |
|
234 globalName replaceAll:$: by:$_ |
|
235 ]. |
|
236 |
|
237 aStream nextPutAll:'#define ',globalName,'_addr '. |
|
238 aStream nextPutAll:(Smalltalk cellAt:aSymbol) printString. |
|
239 aStream cr. |
|
240 |
|
241 aStream nextPutAll:'#define ',globalName,' ( *( (OBJ *) ',globalName,'_addr))'. |
|
242 aStream cr |
|
243 |
|
244 "ObjectFileLoader storeGlobalAddressOf:#String on:Transcript" |
|
245 "ObjectFileLoader storeGlobalAddressOf:#Symbol on:Transcript" |
|
246 ! |
|
247 |
|
248 createStubFor:aSelector calling:functionName args:argTypes returning:returnType in:aClass |
|
249 "create a method calling a stub function" |
|
250 |
|
251 |address newMethod s| |
|
252 |
|
253 address := self createStubCalling:functionName args:argTypes returning:returnType. |
|
254 address isNil ifTrue:[^ nil]. |
|
255 |
|
256 newMethod := Method new. |
|
257 newMethod code:address. |
|
258 newMethod category:'external functions'. |
|
259 s := '"calls external function |
|
260 |
|
261 ' , (self cTypeFor:returnType) , ' ' , functionName , '( '. |
|
262 argTypes notNil ifTrue:[ |
|
263 argTypes do:[:type | |
|
264 s := s , (self cTypeFor:type) , ' ' |
|
265 ] |
|
266 ]. |
|
267 s := s , ') |
|
268 "'. |
|
269 newMethod source:s. |
|
270 newMethod numberOfMethodVars:0. |
|
271 newMethod stackSize:0. |
|
272 |
|
273 aClass class addSelector:aSelector withMethod:newMethod. |
|
274 |
|
275 SilentLoading ifFalse:[ |
|
276 Transcript showCr:('created stub: ',aClass class name,' ', aSelector) |
|
277 ]. |
|
278 |
|
279 ^ newMethod |
|
280 |
|
281 "ObjectFileLoader createStubFor:#printf: |
|
282 calling:'printf' |
|
283 args:#(String) |
|
284 returning:nil |
|
285 in:TestClass" |
|
286 "ObjectFileLoader createStubFor:#printf:with: |
|
287 calling:'printf' |
|
288 args:#(String SmallInteger) |
|
289 returning:nil |
|
290 in:TestClass" |
|
291 ! |
|
292 |
|
293 createStubCalling:functionName args:argTypes returning:returnType |
|
294 "create a stub function for calling functionName - return the address of the |
|
295 function in core or nil on error" |
|
296 |
|
297 |baseName p t l handle address stubName| |
|
298 |
|
299 stubName := 'stub000' , (StubNr printStringRadix:16). |
|
300 stubName := stubName copyFrom:(stubName size - 7). |
|
301 |
|
302 baseName := self createStubSource:stubName calling:functionName args:argTypes returning:returnType. |
|
303 baseName isNil ifTrue:[^ nil]. |
|
304 |
|
305 "compile it ..." |
|
306 Verbose ifTrue:[ |
|
307 Transcript showCr:'compiling stub ...', baseName. Transcript endEntry |
|
308 ]. |
|
309 |
|
310 (OperatingSystem executeCommand:('make /tmp/' , baseName , '.o')) ifFalse:[ |
|
311 Transcript showCr:'compilation error.'. |
|
312 ^ nil |
|
313 ]. |
|
314 OperatingSystem executeCommand:('mv ' , baseName , '.o /tmp/' , baseName , '.o'). |
|
315 Verbose ifFalse:[ |
|
316 OperatingSystem executeCommand:('rm /tmp/' , baseName , '.c'). |
|
317 ]. |
|
318 |
|
319 (OperatingSystem getOSType = 'sys5.4') ifTrue:[ |
|
320 "make it a sharable object" |
|
321 |
|
322 Verbose ifTrue:[ |
|
323 Transcript showCr:'makeing shared object stub ...', baseName. Transcript endEntry. |
|
324 ]. |
|
325 OperatingSystem executeCommand:('ld -G -o /tmp/',baseName,'.so /tmp/',baseName,'.o'). |
|
326 |
|
327 "attach to it" |
|
328 handle := self openDynamicObject:('/tmp/',baseName,'.so'). |
|
329 handle isNil ifTrue:[ |
|
330 Transcript showCr:('dlopen error:', '/tmp/',baseName,'.so'). |
|
331 ^ nil |
|
332 ]. |
|
333 "find the stubs address" |
|
334 address := self getSymbol:stubName from:handle. |
|
335 address isNil ifTrue:[ |
|
336 Transcript showCr:'dlsym failed'. |
|
337 ^ nil |
|
338 ] |
|
339 ]. |
|
340 |
|
341 ((OperatingSystem getOSType = 'sunos') |
|
342 or:[OperatingSystem getOSType = 'linux']) ifTrue:[ |
|
343 "load it" |
|
344 (self loadFile:('/tmp/' , baseName , '.o')) ifFalse:[ |
|
345 Transcript showCr:'load error.'. |
|
346 ^ nil |
|
347 ]. |
|
348 |
|
349 "find the stubs address (use nm to get the address)" |
|
350 t := Text new. |
|
351 p := PipeStream readingFrom:('nm SymbolTable|grep ' , stubName , ' |grep T'). |
|
352 [p atEnd] whileFalse:[ |
|
353 l := p nextLine. |
|
354 l notNil ifTrue:[ |
|
355 t add:l |
|
356 ] |
|
357 ]. |
|
358 p close. |
|
359 (t size == 1) ifFalse:[ |
|
360 Transcript showCr:('oops, ' , stubName , ' not in name-list.'). |
|
361 ^ nil |
|
362 ]. |
|
363 address := Integer readFrom:(ReadStream on:(t at:1)) radix:16 |
|
364 ]. |
|
365 |
|
366 address isNil ifTrue:[ |
|
367 Transcript showCr:'no way to dynamically load objects'. |
|
368 ^ nil |
|
369 ]. |
|
370 |
|
371 Verbose ifTrue:[ |
|
372 Transcript show:'stub ' , stubName , ' address:'. |
|
373 Transcript showCr:(address printStringRadix:16). |
|
374 ]. |
|
375 |
|
376 StubNr := StubNr + 1. |
|
377 ^ address |
|
378 |
|
379 "ObjectFileLoader createStubCalling:'printf' args:#(String) returning:nil" |
|
380 ! |
|
381 |
|
382 createStubSource:stubName calling:functionName args:argTypes returning:returnType |
|
383 "create a temp file with stub-code - return base-filename or nil" |
|
384 |
|
385 |pid baseName index aStream argName| |
|
386 |
|
387 pid := OperatingSystem getProcessId printString. |
|
388 baseName := 'stc' , pid. |
|
389 aStream := FileStream newFileNamed:('/tmp/' , baseName , '.c'). |
|
390 aStream nextPutAll:' |
|
391 #include <stc.h> |
|
392 '. |
|
393 |
|
394 OperatingSystem getOSType = 'sys5.4' ifTrue:[ |
|
395 self storeGlobalAddressesOn:aStream. |
|
396 ]. |
|
397 |
|
398 aStream nextPutAll:' |
|
399 ' , stubName , '(self, __sel, SND_COMMA __srch, __pI, |
|
400 __a1, __a2, __a3, __a4, __a5, __a6, __a7, __a8) |
|
401 OBJ __a1, __a2, __a3, __a4, __a5, __a6, __a7, __a8; |
|
402 OBJ __sel, __srch; |
|
403 SENDER_DECL |
|
404 { |
|
405 extern OBJ _ISKINDOF_(), ExternalStream; |
|
406 '. |
|
407 |
|
408 returnType notNil ifTrue:[ |
|
409 aStream nextPutAll:' '. |
|
410 aStream nextPutAll:(self cTypeFor:returnType). |
|
411 aStream nextPutAll:' __ret;'. |
|
412 aStream cr |
|
413 ]. |
|
414 |
|
415 "gen type checking code" |
|
416 argTypes notNil ifTrue:[ |
|
417 index := 0. |
|
418 argTypes do:[:argType | |
|
419 (index + 1) timesRepeat:[ aStream nextPutAll:' ']. |
|
420 argName := '__a' , (index + 1) printString. |
|
421 aStream nextPutAll:'if ('. |
|
422 (self checkType:argType name:argName on:aStream) ifFalse:[^ nil]. |
|
423 aStream nextPutAll:') {'. |
|
424 aStream cr. |
|
425 index := index + 1 |
|
426 ] |
|
427 ]. |
|
428 "call the function" |
|
429 |
|
430 (index + 1) timesRepeat:[ aStream nextPutAll:' ']. |
|
431 returnType notNil ifTrue:[ |
|
432 aStream nextPutAll:'__ret = ' |
|
433 ]. |
|
434 aStream nextPutAll:functionName , '('. |
|
435 argTypes notNil ifTrue:[ |
|
436 index := 0. |
|
437 argTypes do:[:argType | |
|
438 argName := '__a' , (index + 1) printString. |
|
439 self convertStToC:argType name:argName on:aStream. |
|
440 index := index + 1. |
|
441 (index == argTypes size) ifFalse:[ |
|
442 aStream nextPutAll:',' |
|
443 ] |
|
444 ] |
|
445 ]. |
|
446 aStream nextPutAll:');'. aStream cr. |
|
447 |
|
448 argTypes notNil ifTrue:[ |
|
449 argTypes size timesRepeat:[ |
|
450 index timesRepeat:[ aStream nextPutAll:' ']. |
|
451 aStream nextPutAll:'}'. aStream cr. |
|
452 index := index - 1 |
|
453 ] |
|
454 ]. |
|
455 |
|
456 returnType notNil ifTrue:[ |
|
457 aStream nextPutAll:' return '. |
|
458 self convertCToSt:returnType name:'__ret' on:aStream. |
|
459 aStream nextPutAll:';' |
|
460 ] ifFalse:[ |
|
461 aStream nextPutAll:' return self;' |
|
462 ]. |
|
463 aStream cr. |
|
464 |
|
465 aStream nextPutAll:'}'. aStream cr. |
|
466 aStream close. |
|
467 ^ baseName |
|
468 |
|
469 "ObjectFileLoader createStubSource:'stub1' calling:'printMessage' args:#(String) returning:nil" |
|
470 "ObjectFileLoader createStubSource:'stub2' calling:'printMessage2' args:#(String SmallInteger) returning:#String" |
|
471 "ObjectFileLoader createStubSource:'stub3' calling:'sqrt' args:#(Float) returning:#Float" |
|
472 "ObjectFileLoader createStubSource:'stub4' calling:'checking' args:#(SmallInteger SmallInteger) returning:#Boolean" |
|
473 "ObjectFileLoader createStubSource:'stub5' calling:'fprintf' args:#(ExternalStream String) returning:#SmallInteger" |
|
474 ! |
|
475 |
|
476 checkType:argType name:argName on:aStream |
|
477 "generate type checking code" |
|
478 |
|
479 (argType == #SmallInteger) ifTrue:[ |
|
480 aStream nextPutAll:'_isSmallInteger(' , argName , ')'. |
|
481 ^ true |
|
482 ]. |
|
483 (argType == #Float) ifTrue:[ |
|
484 aStream nextPutAll:'__isFloat(' , argName , ')'. |
|
485 ^ true |
|
486 ]. |
|
487 (argType == #Character) ifTrue:[ |
|
488 aStream nextPutAll:'__isCharacter(' , argName , ')'. |
|
489 ^ true |
|
490 ]. |
|
491 (argType == #String) ifTrue:[ |
|
492 aStream nextPutAll:'__isString(' , argName , ')'. |
|
493 ^ true |
|
494 ]. |
|
495 (argType == #Symbol) ifTrue:[ |
|
496 aStream nextPutAll:'__isSymbol(' , argName , ')'. |
|
497 ^ true |
|
498 ]. |
|
499 (argType == #Boolean) ifTrue:[ |
|
500 aStream nextPutAll:'((' , argName , '==true)'. |
|
501 aStream nextPutAll:'||(' , argName , '==false))'. |
|
502 ^ true |
|
503 ]. |
|
504 (argType == #ByteArray) ifTrue:[ |
|
505 aStream nextPutAll:'__isByteArray(' , argName , ')'. |
|
506 ^ true |
|
507 ]. |
|
508 (argType == #ExternalStream) ifTrue:[ |
|
509 aStream nextPutAll:'(_ISKINDOF_(' , argName , ', SND_COMMA ExternalStream)==true)'. |
|
510 ^ true |
|
511 ]. |
|
512 self error:'argType ' , argType, ' not (yet) supported'. |
|
513 ^ false |
|
514 ! |
|
515 |
|
516 convertStToC:stType name:argName on:aStream |
|
517 "generate type conversion code" |
|
518 |
|
519 |idx| |
|
520 |
|
521 (stType == #SmallInteger) ifTrue:[ |
|
522 aStream nextPutAll:'_intVal(' , argName , ')'. |
|
523 ^ true |
|
524 ]. |
|
525 (stType == #Float) ifTrue:[ |
|
526 aStream nextPutAll:'_floatVal(' , argName , ')'. |
|
527 ^ true |
|
528 ]. |
|
529 (stType == #Character) ifTrue:[ |
|
530 aStream nextPutAll:'_characterVal(' , argName , ')'. |
|
531 ^ true |
|
532 ]. |
|
533 (stType == #String) ifTrue:[ |
|
534 aStream nextPutAll:'_stringVal(' , argName , ')'. |
|
535 ^ true |
|
536 ]. |
|
537 (stType == #Symbol) ifTrue:[ |
|
538 aStream nextPutAll:'_stringVal(' , argName , ')'. |
|
539 ^ true |
|
540 ]. |
|
541 (stType == #Boolean) ifTrue:[ |
|
542 aStream nextPutAll:'((' , argName , '==true) ? 1 : 0)'. |
|
543 ^ true |
|
544 ]. |
|
545 (stType == #ByteArray) ifTrue:[ |
|
546 aStream nextPutAll:'(_ByteArrayInstPtr(' , argName , ')->ba_element)'. |
|
547 ^ true |
|
548 ]. |
|
549 (stType == #ExternalStream) ifTrue:[ |
|
550 "find the file-pointer inst-var" |
|
551 idx := (ExternalStream allInstVarNames indexOf:'filePointer'). |
|
552 aStream nextPutAll:'_intVal(_InstPtr(' , argName , ')->i_instvars['. |
|
553 aStream nextPutAll:(idx - 1) printString, '])'. |
|
554 ^ true |
|
555 ]. |
|
556 ^ false |
|
557 ! |
|
558 |
|
559 convertCToSt:stType name:argName on:aStream |
|
560 "generate type conversion code" |
|
561 |
|
562 (stType == #SmallInteger) ifTrue:[ |
|
563 aStream nextPutAll:'_MKSMALLINT(' , argName , ')'. |
|
564 ^ true |
|
565 ]. |
|
566 (stType == #Float) ifTrue:[ |
|
567 aStream nextPutAll:'_MKFLOAT(' , argName , ' COMMA_SND)'. |
|
568 ^ true |
|
569 ]. |
|
570 (stType == #Character) ifTrue:[ |
|
571 aStream nextPutAll:'_MKCHARACTER(' , argName , ')'. |
|
572 ^ true |
|
573 ]. |
|
574 (stType == #String) ifTrue:[ |
|
575 aStream nextPutAll:'(' , argName , ' ? _MKSTRING(' , argName , ' COMMA_SND) : nil)'. |
|
576 ^ true |
|
577 ]. |
|
578 (stType == #Symbol) ifTrue:[ |
|
579 aStream nextPutAll:'(' , argName , ' ? _MKSYMBOL(' , argName , ' COMMA_SND) : nil)'. |
|
580 ^ true |
|
581 ]. |
|
582 (stType == #Boolean) ifTrue:[ |
|
583 aStream nextPutAll:'(' , argName , ' ? true : false)'. |
|
584 ^ true |
|
585 ]. |
|
586 ^ false |
|
587 ! |
|
588 |
|
589 cTypeFor:aType |
|
590 "return c-type for an ST-type" |
|
591 |
|
592 (aType == #SmallInteger) ifTrue:[ |
|
593 ^ 'int' |
|
594 ]. |
|
595 (aType == #Boolean) ifTrue:[ |
|
596 ^ 'int' |
|
597 ]. |
|
598 (aType == #Float) ifTrue:[ |
|
599 ^ 'double' |
|
600 ]. |
|
601 (aType == #Character) ifTrue:[ |
|
602 ^ 'char' |
|
603 ]. |
|
604 (aType == #String) ifTrue:[ |
|
605 ^ 'char *' |
|
606 ]. |
|
607 (aType == #Symbol) ifTrue:[ |
|
608 ^ 'char *' |
|
609 ]. |
|
610 (aType == #ByteArray) ifTrue:[ |
|
611 ^ 'unsigned char *' |
|
612 ]. |
|
613 (aType == nil) ifTrue:[ |
|
614 ^ 'void' |
|
615 ]. |
|
616 (aType == #ExternalStream) ifTrue:[ |
|
617 ^ 'void *' "actually its FILE *, but better avoid including stdio.h" |
|
618 ]. |
|
619 self error:'type ' , aType, ' not supported'. |
|
620 ^ '' |
|
621 ! ! |
|
622 |
|
623 !ObjectFileLoader class methodsFor:'loading objects'! |
238 !ObjectFileLoader class methodsFor:'loading objects'! |
624 |
239 |
625 loadFile:oFile with:librariesString |
240 loadFile:oFile with:librariesString |
626 "load in an object files code, linking in libraries" |
241 "load in an object files code, linking in libraries. |
627 |
242 This is only needed if no dynamic link facility exists." |
628 |tmpOfile errStream errors errText ok pid| |
243 |
|
244 |tmpOfile errStream errors errText handle pid cmd| |
629 |
245 |
630 pid := OperatingSystem getProcessId printString. |
246 pid := OperatingSystem getProcessId printString. |
631 tmpOfile := '/tmp/stc_ld' , pid. |
247 tmpOfile := '/tmp/stc_ld' , pid. |
|
248 cmd := 'ld -o ', tmpOfile, ' -r ' , oFile , ' ' , librariesString , '>/tmp/out 2>/tmp/err'. |
632 Verbose ifTrue:[ |
249 Verbose ifTrue:[ |
633 Transcript showCr:'executing: ' , ('ld -o ',tmpOfile,' -r ' , oFile , ' ' , librariesString , '>/tmp/out 2>/tmp/err') |
250 ('executing: ld -o ', cmd) errorPrintNL |
634 ]. |
251 ]. |
635 (OperatingSystem executeCommand:'ld -o ',tmpOfile,' -r ' , oFile , ' ' , librariesString , '>/tmp/out 2>/tmp/err') |
252 (OperatingSystem executeCommand:cmd) ifFalse:[ |
636 ifFalse:[ |
|
637 errStream := FileStream oldFileNamed:'/tmp/err'. |
253 errStream := FileStream oldFileNamed:'/tmp/err'. |
638 errStream isNil ifTrue:[ |
254 errStream isNil ifTrue:[ |
639 self notify:'errors during link.' |
255 self notify:'errors during link.' |
640 ] ifFalse:[ |
256 ] ifFalse:[ |
641 errors := errStream contents. |
257 errors := errStream contents. |
648 OperatingSystem executeCommand:'rm /tmp/err /tmp/out'. |
264 OperatingSystem executeCommand:'rm /tmp/err /tmp/out'. |
649 self notify:('link errors:\\' , errors asString) withCRs |
265 self notify:('link errors:\\' , errors asString) withCRs |
650 ]. |
266 ]. |
651 ^ false |
267 ^ false |
652 ]. |
268 ]. |
653 ok := self loadFile:tmpOfile. |
269 handle := self loadFile:tmpOfile. |
654 OperatingSystem executeCommand:('rm ' , tmpOfile). |
270 OperatingSystem executeCommand:('rm ' , tmpOfile). |
655 ^ ok |
271 ^ handle |
656 ! |
272 ! |
657 |
273 |
658 loadFile:oFile |
274 loadFile:oFile |
659 "load in an object file" |
275 "load in an object file - return a handle or nil. |
660 |
276 This is only needed if no dynamic link facility exists." |
661 | unixCommand errStream errors errText |
277 |
662 text data textSize dataSize dataAddr textAddr newTextSize newDataSize| |
278 |unixCommand errStream errors errText |
|
279 text data textSize dataSize dataAddr textAddr newTextSize newDataSize| |
663 |
280 |
664 "find out, how much memory we need" |
281 "find out, how much memory we need" |
665 |
282 |
666 textSize := ObjectFile textSizeOf:oFile. |
283 textSize := self textSizeOf:oFile. |
667 textSize isNil ifTrue:[ |
284 textSize isNil ifTrue:[ |
668 Transcript showCr:'bad text-size in object file'. |
285 'bad text-size in object file' errorPrintNL. |
669 ^ false |
286 ^ nil |
670 ]. |
287 ]. |
671 Verbose ifTrue:[ |
288 Verbose ifTrue:[ |
672 Transcript showCr:'text-size: ' , (textSize printStringRadix:16) |
289 ('text-size: ' , (textSize printStringRadix:16)) errorPrintNL |
673 ]. |
290 ]. |
674 |
291 |
675 dataSize := ObjectFile dataSizeOf:oFile. |
292 dataSize := self dataSizeOf:oFile. |
676 dataSize isNil ifTrue:[ |
293 dataSize isNil ifTrue:[ |
677 Transcript showCr:'bad data-size in object file'. |
294 'bad data-size in object file' errorPrintNL. |
678 ^ false |
295 ^ nil |
679 ]. |
296 ]. |
680 |
297 |
681 Verbose ifTrue:[ |
298 Verbose ifTrue:[ |
682 Transcript showCr:'data-size: ' , (dataSize printStringRadix:16) |
299 ('data-size: ' , (dataSize printStringRadix:16)) errorPrintNL |
683 ]. |
300 ]. |
684 |
301 |
685 "allocate some memory for text and some for data; |
302 "allocate some memory for text and some for data; |
686 then call linker to link the file to those addresses" |
303 then call linker to link the file to those addresses" |
687 |
304 |
688 self needSeparateIDSpaces ifTrue:[ |
305 self needSeparateIDSpaces ifTrue:[ |
689 text := ExternalBytes newForText:textSize. |
306 text := ExternalBytes newForText:textSize. |
690 text isNil ifTrue:[ |
307 text isNil ifTrue:[ |
691 Transcript showCr:'cannot allocate memory for text'. |
308 'cannot allocate memory for text' errorPrintNL. |
692 ^ false |
309 ^ nil |
693 ]. |
310 ]. |
694 |
311 |
695 Verbose ifTrue:[ |
312 Verbose ifTrue:[ |
696 Transcript showCr:'text: ' , (text address printStringRadix:16) |
313 ('text: ' , (text address printStringRadix:16)) errorPrintNL |
697 ]. |
314 ]. |
698 |
315 |
699 (dataSize ~~ 0) ifTrue:[ |
316 (dataSize ~~ 0) ifTrue:[ |
700 data := ExternalBytes newForData:dataSize. |
317 data := ExternalBytes newForData:dataSize. |
701 (data isNil) ifTrue:[ |
318 (data isNil) ifTrue:[ |
702 Transcript showCr:'cannot allocate memory for data'. |
319 'cannot allocate memory for data' errorPrintNL. |
703 text notNil ifTrue:[text free]. |
320 text notNil ifTrue:[text free]. |
704 ^ false |
321 ^ nil |
705 ]. |
322 ]. |
706 Verbose ifTrue:[ |
323 Verbose ifTrue:[ |
707 Transcript showCr:'data: ' , (data address printStringRadix:16) |
324 ('data: ' , (data address printStringRadix:16)) errorPrintNL |
708 ] |
325 ] |
709 ]. |
326 ]. |
710 dataSize == 0 ifTrue:[ |
327 dataSize == 0 ifTrue:[ |
711 unixCommand := (self absLd:oFile text:text address) |
328 unixCommand := (self absLd:oFile text:text address) , ' >/tmp/out 2>/tmp/err'. |
712 , ' >/tmp/out 2>/tmp/err'. |
|
713 ] ifFalse:[ |
329 ] ifFalse:[ |
714 unixCommand := (self absLd:oFile text:text address |
330 unixCommand := (self absLd:oFile text:text address data:data address) |
715 data:data address) |
|
716 , ' >/tmp/out 2>/tmp/err'. |
331 , ' >/tmp/out 2>/tmp/err'. |
717 ] |
332 ] |
718 ] ifFalse:[ |
333 ] ifFalse:[ |
719 text := ExternalBytes newForText:(textSize + dataSize). |
334 text := ExternalBytes newForText:(textSize + dataSize). |
720 text isNil ifTrue:[ |
335 text isNil ifTrue:[ |
721 Transcript showCr:'cannot allocate memory for text+data'. |
336 'cannot allocate memory for text+data' errorPrintNL. |
722 ^ false |
337 ^ nil |
723 ]. |
338 ]. |
724 Verbose ifTrue:[ |
339 Verbose ifTrue:[ |
725 Transcript showCr:'addr: ' , (text address printStringRadix:16) |
340 ('addr: ' , (text address printStringRadix:16)) errorPrintNL |
726 ]. |
341 ]. |
727 unixCommand := (self absLd:oFile text:text address) |
342 unixCommand := (self absLd:oFile text:text address) , ' >/tmp/out 2>/tmp/err'. |
728 , ' >/tmp/out 2>/tmp/err'. |
|
729 ]. |
343 ]. |
730 |
344 |
731 Verbose ifTrue:[ |
345 Verbose ifTrue:[ |
732 Transcript showCr:'executing: ' , unixCommand |
346 ('executing: ' , unixCommand) errorPrintNL |
733 ]. |
347 ]. |
734 |
348 |
735 'linking ...' printNewline. |
349 'linking ...' printNewline. |
736 (OperatingSystem executeCommand:unixCommand) ifFalse: [ |
350 (OperatingSystem executeCommand:unixCommand) ifFalse: [ |
737 errStream := FileStream oldFileNamed:'/tmp/err'. |
351 errStream := FileStream oldFileNamed:'/tmp/err'. |
911 dataAddr := nil |
522 dataAddr := nil |
912 ]. |
523 ]. |
913 |
524 |
914 Verbose ifTrue:[ |
525 Verbose ifTrue:[ |
915 textAddr notNil ifTrue:[ |
526 textAddr notNil ifTrue:[ |
916 Transcript showCr:'loading ' , textSize printString , ' bytes at ' , (textAddr printStringRadix:16). |
527 ('loading ' , textSize printString , ' bytes at ' , (textAddr printStringRadix:16)) errorPrintNL. |
917 ]. |
528 ]. |
918 dataAddr notNil ifTrue:[ |
529 dataAddr notNil ifTrue:[ |
919 Transcript showCr:'loading ' , dataSize printString , ' bytes at ' , (dataAddr printStringRadix:16). |
530 ('loading ' , dataSize printString , ' bytes at ' , (dataAddr printStringRadix:16)) errorPrintNL. |
920 ]. |
531 ]. |
921 ]. |
532 ]. |
922 |
533 |
923 (ObjectFile loadObjectFile:'a.out' |
534 (self loadObjectFile:'a.out' |
924 textAddr:textAddr textSize:textSize |
535 textAddr:textAddr textSize:textSize |
925 dataAddr:dataAddr dataSize:dataSize) isNil ifTrue: [ |
536 dataAddr:dataAddr dataSize:dataSize) isNil ifTrue: [ |
926 Transcript showCr:'load in error'. |
537 'load error' errorPrintNL. |
927 text notNil ifTrue:[text free]. |
538 text notNil ifTrue:[text free]. |
928 data notNil ifTrue:[data free]. |
539 data notNil ifTrue:[data free]. |
929 ^ false |
540 ^ nil |
930 ]. |
541 ]. |
931 |
542 |
932 'dynamic load successful' printNewline. |
543 'dynamic load successful' errorPrintNL. |
933 |
544 |
934 OperatingSystem executeCommand:'mv a.out SymbolTable'. |
545 OperatingSystem executeCommand:'mv a.out SymbolTable'. |
935 MySymbolTable := 'SymbolTable'. |
546 MySymbolTable := 'SymbolTable'. |
936 ^ true |
547 ^ (Array with:textAddr with:dataAddr) |
937 ! ! |
548 ! ! |
938 |
549 |
939 !ObjectFileLoader class methodsFor:'dynamic class loading'! |
550 !ObjectFileLoader class methodsFor:'dynamic class loading'! |
940 |
551 |
941 loadClass:aClassName fromObjectFile:aFileName |
552 loadClass:aClassName fromObjectFile:aFileName |
942 "load a compiled class (.o-file) into the image" |
553 "load a compiled class (.o-file) into the image" |
943 |
554 |
944 |handle initAddr symName| |
555 |handle initAddr symName newClass list moreHandles| |
945 |
556 |
946 handle := self openDynamicObject:aFileName. |
557 handle := self openDynamicObject:aFileName. |
947 handle isNil ifTrue:[ |
558 handle isNil ifTrue:[ |
948 Transcript showCr:('openDynamic: ',aFileName,' failed.'). |
559 Transcript showCr:('openDynamic: ',aFileName,' failed.'). |
949 ^ nil |
560 ^ nil |
950 ]. |
561 ]. |
|
562 |
|
563 " |
|
564 get the Init-function; let the class install itself |
|
565 " |
951 symName := '_' , aClassName , '_Init'. |
566 symName := '_' , aClassName , '_Init'. |
952 initAddr := self getSymbol:symName from:handle. |
567 initAddr := self getFunction:symName from:handle. |
953 initAddr isNil ifTrue:[ |
568 initAddr isNil ifTrue:[ |
954 "try with added underscore" |
569 "try with added underscore" |
955 symName := '__' , aClassName , '_Init'. |
570 symName := '__' , aClassName , '_Init'. |
956 initAddr := self getSymbol:symName from:handle. |
571 initAddr := self getFunction:symName from:handle. |
|
572 ]. |
|
573 |
|
574 " |
|
575 if there are any undefined symbols, we may have to load more |
|
576 " |
|
577 list := self getListOfUndefinedSymbolsFrom:handle. |
|
578 list notNil ifTrue:[ |
|
579 moreHandles := self loadModulesFromListOfUndefined:list. |
|
580 |
|
581 " |
|
582 now, try again |
|
583 " |
|
584 symName := '_' , aClassName , '_Init'. |
|
585 initAddr := self getFunction:symName from:handle. |
957 initAddr isNil ifTrue:[ |
586 initAddr isNil ifTrue:[ |
958 Transcript showCr:('no symbol: ',symName,' in ',aFileName). |
587 "try with added underscore" |
959 ^ nil |
588 symName := '__' , aClassName , '_Init'. |
960 ]. |
589 initAddr := self getFunction:symName from:handle. |
961 ]. |
590 ]. |
962 self callFunctionAt:initAddr. |
591 ]. |
963 ^ Smalltalk at:aClassName asSymbol |
592 |
|
593 initAddr notNil ifTrue:[ |
|
594 Verbose ifTrue:[ |
|
595 Transcript showCr:'calling init at: ' , (initAddr printStringRadix:16) |
|
596 ]. |
|
597 self callInitFunctionAt:initAddr. |
|
598 (Symbol hasInterned:aClassName) ifTrue:[ |
|
599 newClass := Smalltalk at:aClassName asSymbol ifAbsent:[nil]. |
|
600 newClass notNil ifTrue:[ |
|
601 newClass initialize. |
|
602 "force cache flush" |
|
603 Smalltalk at:aClassName asSymbol put:newClass. |
|
604 Smalltalk changed. |
|
605 ]. |
|
606 ] ifFalse:[ |
|
607 'LOADER: class ' errorPrintNL. aClassName errorPrintNL. |
|
608 ' did not define itself' errorPrintNL |
|
609 " |
|
610 do not unload - could have installed its methods ... |
|
611 " |
|
612 ]. |
|
613 ^ newClass |
|
614 ]. |
|
615 |
|
616 Verbose ifTrue:[ |
|
617 Transcript showCr:('no symbol: ', symName,' in ',aFileName). |
|
618 ]. |
|
619 |
|
620 " |
|
621 unload |
|
622 " |
|
623 moreHandles notNil ifTrue:[ |
|
624 self closeAllDynamicObjects:moreHandles. |
|
625 ]. |
|
626 self closeDynamicObject:handle. |
|
627 ^ nil |
964 |
628 |
965 "ObjectFileLoader loadClass:'Tetris' fromObjectFile:'../clients/Tetris/Tetris.o'" |
629 "ObjectFileLoader loadClass:'Tetris' fromObjectFile:'../clients/Tetris/Tetris.o'" |
966 "ObjectFileLoader loadClass:'TetrisBlock' fromObjectFile:'../clients/Tetris/TBlock.o'" |
630 "ObjectFileLoader loadClass:'TetrisBlock' fromObjectFile:'../clients/Tetris/TBlock.o'" |
|
631 "ObjectFileLoader loadClass:'Foo' fromObjectFile:'classList.o'" |
967 ! |
632 ! |
968 |
633 |
969 loadObjectFile:aFileName |
634 loadObjectFile:aFileName |
970 "load a compiled class (.o-file) into the image; the class name |
635 "load an object file (.o-file) into the image; |
971 is not needed (multiple definitions may be in the file)" |
636 the class name is not needed (multiple definitions may be in the file)." |
972 |
637 |
973 |handle initAddr symName className| |
638 |handle initAddr symName className newClass list| |
974 |
639 |
975 handle := self openDynamicObject:aFileName. |
640 handle := self openDynamicObject:aFileName. |
976 handle isNil ifTrue:[ |
641 handle isNil ifTrue:[ |
977 Transcript showCr:('openDynamic: ',aFileName,' failed.'). |
642 Transcript showCr:('openDynamic: ',aFileName,' failed.'). |
978 ^ nil |
643 ^ nil |
979 ]. |
644 ]. |
980 |
645 |
981 "load worked - now get init functions address" |
646 " |
982 |
647 look for init-function |
|
648 " |
983 className := OperatingSystem baseNameOf:aFileName. |
649 className := OperatingSystem baseNameOf:aFileName. |
984 (className endsWith:'.o') ifTrue:[ |
650 (className endsWith:'.o') ifTrue:[ |
985 className := className copyTo:(className size - 2) |
651 className := className copyTo:(className size - 2) |
986 ]. |
652 ]. |
987 symName := '_' , className , '_Init'. |
653 symName := '_' , className , '_Init'. |
988 initAddr := self getSymbol:symName from:handle. |
654 initAddr := self getFunction:symName from:handle. |
989 |
655 |
990 initAddr isNil ifTrue:[ |
656 initAddr isNil ifTrue:[ |
991 "try with added underscore" |
657 "try with added underscore" |
992 symName := '__' , className , '_Init'. |
658 symName := '__' , className , '_Init'. |
993 initAddr := self getSymbol:symName from:handle. |
659 initAddr := self getFunction:symName from:handle. |
994 initAddr isNil ifTrue:[ |
660 initAddr isNil ifTrue:[ |
995 "try className from fileName" |
661 "try className from fileName" |
996 className := Smalltalk classNameForFile:className. |
662 className := Smalltalk classNameForFile:className. |
997 symName := '_' , className , '_Init'. |
663 symName := '_' , className , '_Init'. |
998 initAddr := self getSymbol:symName from:handle. |
664 initAddr := self getFunction:symName from:handle. |
999 initAddr isNil ifTrue:[ |
665 initAddr isNil ifTrue:[ |
1000 "and with added underscore" |
666 "and with added underscore" |
1001 symName := '__' , className , '_Init'. |
667 symName := '__' , className , '_Init'. |
1002 initAddr := self getSymbol:symName from:handle. |
668 initAddr := self getFunction:symName from:handle. |
1003 initAddr isNil ifTrue:[ |
669 initAddr isNil ifTrue:[ |
1004 Transcript showCr:('no symbol: ',symName,' in ',aFileName). |
670 Transcript showCr:('no symbol: ',symName,' in ',aFileName). |
|
671 " |
|
672 unload |
|
673 " |
|
674 self closeDynamicObject:handle. |
1005 ^ nil |
675 ^ nil |
1006 ]. |
676 ]. |
1007 ]. |
677 ]. |
1008 ]. |
678 ]. |
1009 ]. |
679 ]. |
1010 self callFunctionAt:initAddr. |
680 Verbose ifTrue:[ |
|
681 Transcript showCr:'calling init at:' , (initAddr printStringRadix:16) |
|
682 ]. |
|
683 self callInitFunctionAt:initAddr. |
|
684 |
|
685 (Symbol hasInterned:className) ifTrue:[ |
|
686 newClass := Smalltalk at:className asSymbol ifAbsent:[nil]. |
|
687 newClass notNil ifTrue:[ |
|
688 newClass initialize. |
|
689 "force cache flush" |
|
690 Smalltalk at:className asSymbol put:newClass. |
|
691 Smalltalk changed. |
|
692 ]. |
|
693 ]. |
|
694 ^ newClass |
|
695 ! |
|
696 |
|
697 loadCPlusPlusObjectFile:aFileName |
|
698 "load a c++ object file (.o-file) into the image" |
|
699 |
|
700 |handle initAddr symName className newClass list| |
|
701 |
|
702 handle := self openDynamicObject:aFileName. |
|
703 handle isNil ifTrue:[ |
|
704 Transcript showCr:('openDynamic: ',aFileName,' failed.'). |
|
705 ^ nil |
|
706 ]. |
|
707 |
|
708 list := self namesMatching:'__GLOBAL_$I*' in:aFileName. |
|
709 list size == 1 ifTrue:[ |
|
710 "/ (self isCPlusPlusObject:handle) ifTrue:[ |
|
711 Verbose ifTrue:[ |
|
712 Transcript showCr:'a c++ object file' |
|
713 ]. |
|
714 " |
|
715 what I would like to get is the CTOR_LIST, |
|
716 and call each function. |
|
717 But dld cannot (currently) handle SET-type symbols, therefore |
|
718 we search (using nm) for all __GLOBAL_$I* syms, get their values |
|
719 and call them each |
|
720 " |
|
721 "/ list := self namesMatching:'__GLOBAL_$I*' in:aFileName. |
|
722 |
|
723 "/ initAddr := self getFunction:'__CTOR_LIST__' from:handle. |
|
724 "/ Verbose ifTrue:[ |
|
725 "/ Transcript showCr:'calling CTORs at:' , (initAddr printStringRadix:16) |
|
726 "/ ]. |
|
727 |
|
728 initAddr := self getFunction:list first from:handle. |
|
729 initAddr isNil ifTrue:[ |
|
730 " |
|
731 try with added underscore |
|
732 " |
|
733 initAddr := self getFunction:('_' , list first) from:handle. |
|
734 ]. |
|
735 (initAddr isNil and:[list first startsWith:'_']) ifTrue:[ |
|
736 " |
|
737 try with removed underscore |
|
738 " |
|
739 initAddr := self getFunction:(list first copyFrom:2) from:handle. |
|
740 ]. |
|
741 initAddr isNil ifTrue:[ |
|
742 Verbose ifTrue:[ |
|
743 Transcript showCr:'no CTOR-func found (' , list first , ')' |
|
744 ]. |
|
745 self closeDynamicObject:aFileName. |
|
746 ^ nil |
|
747 ]. |
|
748 Verbose ifTrue:[ |
|
749 Transcript showCr:'calling CTORs at:' , (initAddr printStringRadix:16) |
|
750 ]. |
|
751 self callFunctionAt:initAddr forceOld:false arg:0. |
|
752 Verbose ifTrue:[ |
|
753 Transcript showCr:'done with CTORs.' |
|
754 ]. |
|
755 |
|
756 " |
|
757 cannot create a CPlusPlus class automatically (there could be more than |
|
758 one classes in it too ...) |
|
759 " |
|
760 ^ handle |
|
761 ]. |
|
762 |
|
763 |
|
764 Verbose ifTrue:[ |
|
765 Transcript showCr:'unknown object file' |
|
766 ]. |
|
767 self closeDynamicObject:aFileName. |
|
768 ^ nil |
|
769 ! |
|
770 |
|
771 loadModulesFromListOfUndefined:list |
|
772 "try to figure out what has to be loaded to resolve symbols from list. |
|
773 return a list of handles of loaded objects |
|
774 " |
|
775 |inits classNames moreHandles| |
|
776 |
|
777 inits := list select:[:symbol | symbol notNil and:[symbol endsWith:'_Init']]. |
|
778 inits notNil ifTrue:[ |
|
779 classNames := inits collect:[:symbol | |
|
780 (symbol startsWith:'___') ifTrue:[ |
|
781 symbol copyFrom:4 to:(symbol size - 5) |
|
782 ] ifFalse:[ |
|
783 (symbol startsWith:'__') ifTrue:[ |
|
784 symbol copyFrom:3 to:(symbol size - 5) |
|
785 ] ifFalse:[ |
|
786 (symbol startsWith:'_') ifTrue:[ |
|
787 symbol copyFrom:2 to:(symbol size - 5) |
|
788 ] ifFalse:[ |
|
789 symbol |
|
790 ] |
|
791 ] |
|
792 ] |
|
793 ]. |
|
794 " |
|
795 autoload those classes |
|
796 " |
|
797 classNames do:[:aClassName | |
|
798 aClassName knownAsSymbol ifTrue:[ |
|
799 (Smalltalk includesKey:aClassName asSymbol) ifTrue:[ |
|
800 'autoloading ' print. aClassName printNL. |
|
801 (Smalltalk at:aClassName asSymbol) autoload |
|
802 ] |
|
803 ] |
|
804 ] |
|
805 ]. |
|
806 ^ nil |
1011 ! ! |
807 ! ! |
1012 |
808 |
1013 !ObjectFileLoader class methodsFor:'dynamic object access'! |
809 !ObjectFileLoader class methodsFor:'dynamic object access'! |
1014 |
810 |
1015 openDynamicObject:pathName |
811 openDynamicObject:pathName |
1016 "open an object-file (map into my address space). |
812 "open an object-file (load/map into my address space). |
1017 Return a non-nil handle if ok, nil otherwise. |
813 Return a non-nil handle if ok, nil otherwise. |
1018 This function is not supported on all architectures." |
814 No bindings are done - only a pure load is performed. |
|
815 This function is not supported on all architectures. |
|
816 " |
1019 |
817 |
1020 |handle| |
818 |handle| |
1021 |
819 |
|
820 Verbose ifTrue:[ |
|
821 Transcript showCr:'openDynamic: ' , pathName |
|
822 ]. |
|
823 |
1022 handle := self primOpenDynamicObject:pathName into:(Array new:2). |
824 handle := self primOpenDynamicObject:pathName into:(Array new:2). |
|
825 handle isNil ifTrue:[ |
|
826 Verbose ifTrue:[ |
|
827 Transcript showCr:'no dynamic load facility or load failed.'. |
|
828 ]. |
|
829 "try it the hard way" |
|
830 handle := self loadFile:pathName. |
|
831 ]. |
1023 ^ handle |
832 ^ handle |
1024 |
833 |
1025 "sys5.4: |
834 "sys5.4: |
1026 |handle| |
835 |handle| |
1027 handle := ObjectFileLoader openDynamicObject:'../stc/mod1.so'. |
836 handle := ObjectFileLoader openDynamicObject:'../stc/mod1.so'. |
1028 ObjectFileLoader getSymbol:'module1' from:handle |
837 ObjectFileLoader getFunction:'module1' from:handle |
1029 " |
838 " |
1030 "next: |
839 "next: |
1031 |handle| |
840 |handle| |
1032 handle := ObjectFileLoader openDynamicObject:'../goodies/Path/AbstrPath.o'. |
841 handle := ObjectFileLoader openDynamicObject:'../goodies/Path/AbstrPath.o'. |
1033 ObjectFileLoader getSymbol:'__AbstractPath_Init' from:handle |
842 ObjectFileLoader getFunction:'__AbstractPath_Init' from:handle |
1034 " |
843 " |
1035 "GLD: |
844 "GLD: |
1036 |handle| |
845 |handle| |
1037 handle := ObjectFileLoader openDynamicObject:'../clients/Tetris/Tetris.o'. |
846 handle := ObjectFileLoader openDynamicObject:'../clients/Tetris/Tetris.o'. |
1038 ObjectFileLoader getSymbol:'__TetrisBlock_Init' from:handle |
847 ObjectFileLoader getFunction:'__TetrisBlock_Init' from:handle |
1039 " |
848 " |
1040 ! |
849 ! |
1041 |
850 |
1042 primOpenDynamicObject:pathName into:aBuffer |
851 primOpenDynamicObject:pathName into:aBuffer |
1043 "open an object-file (map into my address space). |
852 "open an object-file (map into my address space). |
1044 This function is not supported on all architectures. |
853 This function is not supported on all architectures. |
1045 Dont depend on the returned value or class of it, it depends |
854 Dont depend on the values or types returned in aBuffer, |
1046 on the underlying dynamic load package." |
855 it depends on the underlying dynamic load package." |
1047 |
856 |
1048 %{ /* UNLIMITEDSTACK */ |
857 %{ /* UNLIMITEDSTACK */ |
1049 |
858 |
1050 #ifdef GNU_DL |
859 #ifdef GNU_DL |
1051 # include "dld.h" |
860 # include "dld.h" |
|
861 static firstCall = 1; |
|
862 extern char *__myName__; |
|
863 |
|
864 if (firstCall) { |
|
865 firstCall = 0; |
|
866 (void) dld_init (__myName__); |
|
867 } |
|
868 |
1052 if (__isString(pathName)) { |
869 if (__isString(pathName)) { |
1053 if (dld_link(_stringVal(pathName))) { |
870 if (dld_link(_stringVal(pathName))) { |
1054 dld_perror("cant link"); |
871 dld_perror("cant link"); |
1055 RETURN ( nil ); |
872 RETURN ( nil ); |
1056 } |
873 } |
1175 int val; |
993 int val; |
1176 |
994 |
1177 if (_isSmallInteger(low) && _isSmallInteger(hi)) { |
995 if (_isSmallInteger(low) && _isSmallInteger(hi)) { |
1178 val = (_intVal(hi) << 16) + _intVal(low); |
996 val = (_intVal(hi) << 16) + _intVal(low); |
1179 h = (void *)(val); |
997 h = (void *)(val); |
1180 printf("close handle = %x\n", h); |
998 if (ObjectFileLoader_Verbose == true) |
|
999 printf("close handle = %x\n", h); |
1181 dlclose(h); |
1000 dlclose(h); |
1182 } |
1001 } |
1183 #endif |
1002 #endif |
1184 %} |
1003 %} |
1185 ! |
1004 ! |
1186 |
1005 |
1187 getSymbol:aString from:handle |
1006 isSmalltalkObject:handle |
1188 "return the address of a symbol from a dynamically loaded object file. |
1007 "return true, if the loaded object is a smalltalk object module" |
|
1008 |
|
1009 "not yet implemented - stc_compiled_smalltalk is a static symbol, |
|
1010 not found in list - need nm-interface, or nlist-walker |
|
1011 " |
|
1012 ^ true. |
|
1013 |
|
1014 (self getSymbol:'__stc_compiled_smalltalk' function:true from:handle) notNil ifTrue:[^ true]. |
|
1015 (self getSymbol:'__stc_compiled_smalltalk' function:false from:handle) notNil ifTrue:[^ true]. |
|
1016 ^ false |
|
1017 ! |
|
1018 |
|
1019 isCPlusPlusObject:handle |
|
1020 "return true, if the loaded object is a c++ object module" |
|
1021 |
|
1022 (self getSymbol:'__gnu_compiled_cplusplus' function:true from:handle) notNil ifTrue:[^ true]. |
|
1023 (self getSymbol:'__CTOR_LIST__' function:true from:handle) notNil ifTrue:[^ true]. |
|
1024 (self getSymbol:'__CTOR_LIST__' function:false from:handle) notNil ifTrue:[^ true]. |
|
1025 (self getSymbol:'__gnu_compiled_cplusplus' function:false from:handle) notNil ifTrue:[^ true]. |
|
1026 ^ false |
|
1027 ! |
|
1028 |
|
1029 namesMatching:aPattern in:aFileName |
|
1030 |p l s addr segment name entry| |
|
1031 |
|
1032 l := OrderedCollection new. |
|
1033 p := PipeStream readingFrom:('nm ' , aFileName). |
|
1034 p isNil ifTrue:[ |
|
1035 ('cannot read names from ' , aFileName) errorPrintNL. |
|
1036 ^ nil |
|
1037 ]. |
|
1038 [p atEnd] whileFalse:[ |
|
1039 entry := p nextLine. |
|
1040 s := ReadStream on:entry. |
|
1041 addr := s nextWord. |
|
1042 segment := s nextWord. |
|
1043 name := s upToEnd withoutSeparators. |
|
1044 (addr notNil and:[segment notNil and:[name notNil]]) ifTrue:[ |
|
1045 (aPattern match:name) ifTrue:[ |
|
1046 l add:name |
|
1047 ] |
|
1048 ] |
|
1049 ]. |
|
1050 p close. |
|
1051 ^ l |
|
1052 ! |
|
1053 |
|
1054 isObjectiveCObject:handle |
|
1055 "not yet implemented" |
|
1056 |
|
1057 ^ false |
|
1058 ! |
|
1059 |
|
1060 getFunction:aString from:handle |
|
1061 "return the address of a function from a dynamically loaded object file. |
|
1062 Handle must be the one returned previously from openDynamicObject. |
|
1063 Return the address of the function, or nil on any error." |
|
1064 |
|
1065 ^ self getSymbol:aString function:true from:handle |
|
1066 ! |
|
1067 |
|
1068 getSymbol:aString function:isFunction from:handle |
|
1069 "return the address of a symbol/function from a dynamically loaded object file. |
1189 Handle must be the one returned previously from openDynamicObject. |
1070 Handle must be the one returned previously from openDynamicObject. |
1190 Return the address of the symbol, or nil on any error." |
1071 Return the address of the symbol, or nil on any error." |
1191 |
1072 |
1192 |low hi lowAddr hiAddr| |
1073 |low hi lowAddr hiAddr| |
1193 |
1074 |
1194 %{ |
1075 %{ /* STACK: 20000 */ |
|
1076 |
1195 #ifdef GNU_DL |
1077 #ifdef GNU_DL |
1196 # include "dld.h" |
1078 # include "dld.h" |
1197 void (*func)(); |
1079 void (*func)(); |
|
1080 unsigned long addr; |
|
1081 char *name; |
1198 |
1082 |
1199 if (__isString(aString)) { |
1083 if (__isString(aString)) { |
1200 func = (void (*) ()) dld_get_func(_stringVal(aString)); |
1084 name = (char *) _stringVal(aString); |
1201 if (func) { |
1085 if (isFunction == false) { |
1202 printf("addr = %x\n", (INT)func); |
1086 addr = dld_get_symbol(name); |
1203 lowAddr = _MKSMALLINT( (INT)func & 0xFFFF ); |
|
1204 hiAddr = _MKSMALLINT( ((INT)func >> 16) & 0xFFFF ); |
|
1205 } else { |
1087 } else { |
1206 dld_perror("get_func"); |
1088 func = (void (*) ()) dld_get_func(name); |
|
1089 if (func) { |
|
1090 if (ObjectFileLoader_Verbose == true) |
|
1091 printf("addr of %s = %x\n", name, (INT)func); |
|
1092 if (dld_function_executable_p(name)) { |
|
1093 lowAddr = _MKSMALLINT( (INT)func & 0xFFFF ); |
|
1094 hiAddr = _MKSMALLINT( ((INT)func >> 16) & 0xFFFF ); |
|
1095 } else { |
|
1096 char **undefNames; |
|
1097 char **nm; |
|
1098 int i; |
|
1099 |
|
1100 if (ObjectFileLoader_Verbose == true) { |
|
1101 printf ("function %s not executable\n", name); |
|
1102 dld_perror("not executable"); |
|
1103 |
|
1104 printf("undefined:\n"); |
|
1105 nm = undefNames = dld_list_undefined_sym(); |
|
1106 for (i=dld_undefined_sym_count; i; i--) { |
|
1107 printf(" %s\n", *nm++); |
|
1108 } |
|
1109 } |
|
1110 free(undefNames); |
|
1111 } |
|
1112 } else { |
|
1113 dld_perror("get_func"); |
|
1114 } |
1207 } |
1115 } |
1208 } |
1116 } |
1209 #endif |
1117 #endif |
1210 %}. |
1118 %}. |
1211 |
1119 |
1315 void (*addr)(); |
1296 void (*addr)(); |
1316 unsigned val; |
1297 unsigned val; |
1317 typedef void (*VOIDFUNC)(); |
1298 typedef void (*VOIDFUNC)(); |
1318 int savInt; |
1299 int savInt; |
1319 extern int _immediateInterrupt; |
1300 extern int _immediateInterrupt; |
|
1301 int prevSpace; |
|
1302 int arg = 0; |
1320 |
1303 |
1321 if (_isSmallInteger(low) && _isSmallInteger(hi)) { |
1304 if (_isSmallInteger(low) && _isSmallInteger(hi)) { |
1322 val = (_intVal(hi) << 16) + _intVal(low); |
1305 val = (_intVal(hi) << 16) + _intVal(low); |
1323 addr = (VOIDFUNC) val; |
1306 addr = (VOIDFUNC) val; |
1324 |
1307 |
|
1308 if (_isSmallInteger(argument)) { |
|
1309 arg = _intVal(argument); |
|
1310 } |
1325 /* |
1311 /* |
1326 * allow function to be interrupted |
1312 * allow function to be interrupted |
1327 */ |
1313 */ |
1328 savInt = _immediateInterrupt; |
1314 savInt = _immediateInterrupt; |
1329 _immediateInterrupt = 1; |
1315 _immediateInterrupt = 1; |
1330 |
1316 |
1331 (*addr)(); |
1317 if (forceOld == true) { |
|
1318 prevSpace = allocForceSpace(OLDSPACE); |
|
1319 (*addr)(arg); |
|
1320 allocForceSpace(prevSpace); |
|
1321 } else { |
|
1322 (*addr)(arg); |
|
1323 } |
1332 |
1324 |
1333 _immediateInterrupt = savInt; |
1325 _immediateInterrupt = savInt; |
1334 } |
1326 } |
1335 %} |
1327 %} |
1336 ! ! |
1328 ! ! |
1337 |
1329 |
|
1330 !ObjectFileLoader class methodsFor:'primitive loading'! |
|
1331 |
|
1332 textSizeOf:aFileName |
|
1333 " |
|
1334 get the size of the text-segment (nBytes) |
|
1335 " |
|
1336 |
|
1337 %{ /* NOCONTEXT */ |
|
1338 #ifdef HAS_DL |
|
1339 /* |
|
1340 * not needed, if dynamic link facilities exist |
|
1341 */ |
|
1342 #else /* no DL-support */ |
|
1343 char *fname; |
|
1344 int fd; |
|
1345 |
|
1346 if (! __isString(aFileName)) { |
|
1347 RETURN (nil); |
|
1348 } |
|
1349 |
|
1350 fname = (char *) _stringVal(aFileName); |
|
1351 |
|
1352 # if defined(A_DOT_OUT) && !defined(ELF) |
|
1353 # if !defined(sco) && !defined(isc) |
|
1354 { |
|
1355 struct exec header; |
|
1356 |
|
1357 if ((fd = open(fname, 0)) < 0) { |
|
1358 fprintf(stderr, "cannot open <%s>\n", fname); |
|
1359 RETURN ( nil ); |
|
1360 } |
|
1361 if (read(fd, &header, sizeof(header)) != sizeof(header)) { |
|
1362 fprintf(stderr, "cannot read header of <%s>\n", fname); |
|
1363 close(fd); |
|
1364 RETURN ( nil ); |
|
1365 } |
|
1366 close(fd); |
|
1367 |
|
1368 if (N_MAGIC(header) != OMAGIC) { |
|
1369 fprintf(stderr, "header is (0%o) %x - should be (0%o)%x\n", |
|
1370 N_MAGIC(header), N_MAGIC(header), |
|
1371 OMAGIC, OMAGIC); |
|
1372 RETURN ( nil ); |
|
1373 } |
|
1374 RETURN ( _MKSMALLINT(header.a_text) ); |
|
1375 } |
|
1376 # endif |
|
1377 # endif |
|
1378 /* |
|
1379 * need support for other headers ... (i.e. coff, elf) |
|
1380 */ |
|
1381 #endif |
|
1382 %}. |
|
1383 ^ self error:'objectFile format not supported' |
|
1384 ! |
|
1385 |
|
1386 dataSizeOf:aFileName |
|
1387 " |
|
1388 get the size of the data-segment (nBytes) |
|
1389 " |
|
1390 |
|
1391 %{ /* NOCONTEXT */ |
|
1392 #ifdef HAS_DL |
|
1393 /* |
|
1394 * not needed, if dynamic link facilities exist |
|
1395 */ |
|
1396 #else /* no DL-support */ |
|
1397 char *fname; |
|
1398 int fd; |
|
1399 |
|
1400 if (! __isString(aFileName)) { |
|
1401 RETURN ( nil ); |
|
1402 } |
|
1403 |
|
1404 fname = (char *) _stringVal(aFileName); |
|
1405 |
|
1406 # if defined(A_DOT_OUT) && !defined(ELF) |
|
1407 # if !defined(sco) && !defined(isc) |
|
1408 { |
|
1409 struct exec header; |
|
1410 unsigned size; |
|
1411 |
|
1412 if ((fd = open(fname, 0)) < 0) { |
|
1413 fprintf(stderr, "cannot open <%s>\n", fname); |
|
1414 RETURN ( nil ); |
|
1415 } |
|
1416 if (read(fd, &header, sizeof(header)) != sizeof(header)) { |
|
1417 fprintf(stderr, "cannot read header of <%s>\n", fname); |
|
1418 close(fd); |
|
1419 RETURN ( nil ); |
|
1420 } |
|
1421 close(fd); |
|
1422 |
|
1423 if (N_MAGIC(header) != OMAGIC) { |
|
1424 fprintf(stderr, "header is (0%o) %x - should be (0%o)%x\n", |
|
1425 N_MAGIC(header), N_MAGIC(header), |
|
1426 OMAGIC, OMAGIC); |
|
1427 RETURN ( nil ); |
|
1428 } |
|
1429 size = header.a_data; |
|
1430 # if defined(sinix) && defined(BSD) |
|
1431 size += header.a_bss; |
|
1432 # endif |
|
1433 RETURN ( _MKSMALLINT(size) ); |
|
1434 } |
|
1435 # endif |
|
1436 # endif |
|
1437 /* |
|
1438 * need support for other headers ... (i.e. coff, elf) |
|
1439 */ |
|
1440 #endif |
|
1441 %} |
|
1442 . |
|
1443 ^ self error:'objectFile format not supported' |
|
1444 ! |
|
1445 |
|
1446 loadObjectFile:aFileName textAddr:textAddr textSize:textSize |
|
1447 dataAddr:dataAddr dataSize:dataSize |
|
1448 |
|
1449 "the object in aFileName must have been linked for |
|
1450 absolute address textAddr/dataAddr (using ld -A). |
|
1451 Load the contents from the file. Memory must have previously |
|
1452 been allocated using ExternalBytes." |
|
1453 |
|
1454 %{ /* NOCONTEXT */ |
|
1455 #ifdef HAS_DL |
|
1456 /* |
|
1457 * not needed, if dynamic link facilities exist |
|
1458 */ |
|
1459 #else /* no DL-support */ |
|
1460 if (! __isString(aFileName)) { |
|
1461 RETURN ( nil ); |
|
1462 } |
|
1463 |
|
1464 # if defined(A_DOT_OUT) && !defined(ELF) |
|
1465 # if !defined(sco) && !defined(isc) |
|
1466 { |
|
1467 char *fname = (char *) _stringVal(aFileName); |
|
1468 unsigned taddr, daddr; |
|
1469 unsigned tsize, dsize; |
|
1470 unsigned toffset = 0; |
|
1471 unsigned doffset = 0; |
|
1472 int fd; |
|
1473 struct exec header; |
|
1474 char *cp; |
|
1475 int bssCount; |
|
1476 unsigned magic = OMAGIC; |
|
1477 int nread; |
|
1478 |
|
1479 taddr = _isSmallInteger(textAddr) ? (unsigned) _intVal(textAddr) : 0; |
|
1480 daddr = _isSmallInteger(dataAddr) ? (unsigned) _intVal(dataAddr) : 0; |
|
1481 tsize = _isSmallInteger(textSize) ? _intVal(textSize) : 0; |
|
1482 dsize = _isSmallInteger(dataSize) ? _intVal(dataSize) : 0; |
|
1483 |
|
1484 if ((fd = open(fname, 0)) < 0) { |
|
1485 fprintf(stderr, "cannot open <%s>\n", fname); |
|
1486 RETURN ( nil ); |
|
1487 } |
|
1488 if (read(fd, &header, sizeof(header)) != sizeof(header)) { |
|
1489 fprintf(stderr, "cannot read header of <%s>\n", fname); |
|
1490 close(fd); |
|
1491 RETURN ( nil ); |
|
1492 } |
|
1493 if (N_MAGIC(header) != magic) { |
|
1494 fprintf(stderr, "header is (0%o) %x should be (0%o) %x\n", |
|
1495 N_MAGIC(header), N_MAGIC(header), |
|
1496 magic, magic); |
|
1497 close(fd); |
|
1498 RETURN ( nil ); |
|
1499 } |
|
1500 |
|
1501 /* |
|
1502 * some linkers produce a huge output file, with zeros up to the |
|
1503 * real code ... - thats what toffset, doffset are for. |
|
1504 */ |
|
1505 # if defined(sinix) && defined(BSD) |
|
1506 toffset = N_TXTADDR(header); |
|
1507 doffset = toffset + taddr + tsize /* - 0x800 */; |
|
1508 daddr = taddr + tsize; |
|
1509 # else |
|
1510 # if defined(mips) && defined(ultrix) |
|
1511 toffset = N_TXTOFF(header.ex_f, header.ex_o); |
|
1512 doffset = toffset + tsize; |
|
1513 daddr = taddr + tsize; |
|
1514 # else |
|
1515 # if defined(N_TXTOFF) |
|
1516 toffset = N_TXTOFF(header); |
|
1517 doffset = N_DATOFF(header); |
|
1518 daddr = taddr + tsize; |
|
1519 # else |
|
1520 fprintf(stderr, "dont know text/data offsets in objectfile\n"); |
|
1521 RETURN ( nil ); |
|
1522 # endif |
|
1523 # endif |
|
1524 # endif |
|
1525 |
|
1526 # ifdef SUPERDEBUG |
|
1527 printf("toffs:%x taddr:%x tsize:%d doffs:%x daddr:%x dsize:%d\n", |
|
1528 toffset, taddr, tsize, doffset,daddr, dsize); |
|
1529 # endif |
|
1530 |
|
1531 if (lseek(fd, (long)toffset, 0) < 0) { |
|
1532 fprintf(stderr, "cannot seek to text\n"); |
|
1533 close(fd); |
|
1534 RETURN ( nil ); |
|
1535 } |
|
1536 if ((nread = read(fd, taddr, tsize)) != tsize) { |
|
1537 perror("read"); |
|
1538 fprintf(stderr, "cannot read text wanted:%d got:%d\n", tsize, nread); |
|
1539 close(fd); |
|
1540 RETURN ( nil ); |
|
1541 } |
|
1542 |
|
1543 # ifdef SUPERDEBUG |
|
1544 printf("1st bytes of text: %02x %02x %02x %02x\n", |
|
1545 *((char *)taddr) & 0xFF, *((char *)taddr+1) & 0xFF, |
|
1546 *((char *)taddr+2) & 0xFF, *((char *)taddr+3) & 0xFF); |
|
1547 # endif |
|
1548 |
|
1549 if (dsize) { |
|
1550 if (lseek(fd, (long)doffset, 0) < 0) { |
|
1551 fprintf(stderr, "cannot seek to data\n"); |
|
1552 close(fd); |
|
1553 RETURN ( nil ); |
|
1554 } |
|
1555 |
|
1556 if (read(fd, daddr, dsize) != dsize) { |
|
1557 fprintf(stderr, "cannot read data\n"); |
|
1558 close(fd); |
|
1559 RETURN ( nil ); |
|
1560 } |
|
1561 # ifdef SUPERDEBUG |
|
1562 { |
|
1563 char *ptr; |
|
1564 int i; |
|
1565 |
|
1566 ptr = (char *)daddr; |
|
1567 fprintf(stderr, "bytes of data (at %x):\n", ptr); |
|
1568 for (i=dsize; i>0; i--, ptr++) |
|
1569 printf("%02x ", *ptr & 0xFF); |
|
1570 } |
|
1571 # endif |
|
1572 } |
|
1573 close(fd); |
|
1574 |
|
1575 # ifdef NOTDEF |
|
1576 if (header.a_bss != 0) { |
|
1577 fprintf(stderr, "warning: bss not empty\n"); |
|
1578 cp = ((char *)daddr) + header.a_data; |
|
1579 for (bssCount=header.a_bss; bssCount; bssCount--) |
|
1580 *cp++ = 0; |
|
1581 } |
|
1582 # endif |
|
1583 } |
|
1584 RETURN ( self ); |
|
1585 # endif |
|
1586 # endif |
|
1587 /* |
|
1588 * need support for other headers ... (i.e. coff, elf) |
|
1589 */ |
|
1590 #endif |
|
1591 %}. |
|
1592 ^ self error:'objectFile format not supported' |
|
1593 ! ! |
|
1594 |
1338 ObjectFileLoader initialize! |
1595 ObjectFileLoader initialize! |