650 likes | 918 Views
Linking to VC++. Section 8.6 and chapter 12 in Irvine. Preliminary material about the linker.
E N D
Linking to VC++ Section 8.6 and chapter 12 in Irvine
Preliminary material about the linker • Extern: any symbol used in this module but defined elsewhere must be declared extern (with its type specified) so the linker can resolve the reference. The extern must appear in the appropriate segment. • Public: any symbol defined in this module but needed elsewhere must be declared public so the linker knows to use its address in other modules. • Symbols may be declared public and not used elsewhere. Symbols declared as Extern must be defined elsewhere and the addressing must be resolved at link time.
More remarks • Ml.exe is the assembler. • Various switches are used in the assembly some of which get explained later on. In particular, it is possible to compile C modules into obj files for linkage to assembly modules. This is shown later in the show. • Para means paragraph boundary. • Older version of the assembler used cseg, dseg, sseg and so on for code segment, data segment, stack segment etc. • The assume directive, which we haven’t used, tells the assembler to assume that the various segment registers will be pointing at the indicated segments for purposes of assembly. (The assume does not point them there, it is up to the programmer to do that.) • The underscore notation is used to indicate (assembly) labels which will be referenced from C and whose addresses the linker must resolve.
A main using public and extern .model small .stack 100h .386 dseg segment para public 'data' message byte 0ah,0dh,"hello$" dseg ends extern Var1:word, Var2:word, Proc1:near CSEG segment para public 'code' assume cs:cseg, ds:dseg main proc mov ax,dseg mov ds,ax mov Var1, 20 mov Var2, 45 call Proc1 mov dx,var1 mov ah,2 int 21h mov dx,offset message mov ah,9 int 21h mov ax,4c00h int 21h main endp CSEG ends end main
sub public Var1, Var2, Proc1 DSEG segment para public 'data' Var1 word ? Var2 word ? DSEG ends CSEG segment para public 'code' assume cs:cseg, ds:dseg Proc1 proc near mov ax, Var1 add ax, Var2 mov Var1, ax ret Proc1 endp CSEG ends end
Assemble and link main and sub C:\Masm615\Examples\ch08>ML /nologo -Zi -c -Fl -Sg main.asm Assembling: main.asm C:\Masm615\Examples\ch08>link main sub Microsoft (R) Segmented Executable Linker Version 5.60.339 Dec 5 1994 Copyright (C) Microsoft Corp 1984-1993. All rights reserved. Run File [main.exe]: List File [nul.map]: Libraries [.lib]: Definitions File [nul.def]: C:\Masm615\Examples\ch08>main A hello C:\Masm615\Examples\ch08>
Another example: a concatenating sub .model small .data extrn finalstring:byte .code public concat concat proc cld mov di, seg finalstring mov es,di mov di,offset finalstring mov si,ax s1loop: lodsb and al,al jz dos2 stosb jmp s1loop dos2: mov si,bx s2loop: lodsb stosb and al,al jnz s2loop ret concat endp end
Main for 2nd example .model small .stack 100h .data s1 byte 'hello',0;;;;;we will concatenate the two strings with a proc call s2 byte ' world',0ah,0dh,'$',0 public finalstring finalstring byte 50 dup (?) .code extern concat:proc main proc mov ax,@data mov ds,ax mov ax,offset s1 mov bx, offset s2 call concat mov ah,9 mov dx, offset finalstring int 21h mov ax,4c00h int 21h main endp end main
Assemble and run of ex #2 C:\MASM615>ml -c -Cx -Fl -Zi mainprog.asm Microsoft (R) Macro Assembler Version 6.15.8803 Copyright (C) Microsoft Corp 1981-2000. All rights reserved. Assembling: mainprog.asm C:\MASM615>ml -c -Cx -Fl -Zi subprog.asm Microsoft (R) Macro Assembler Version 6.15.8803 Copyright (C) Microsoft Corp 1981-2000. All rights reserved. Assembling: subprog.asm subprog.asm(12) : error A2008: syntax error : in instruction C:\MASM615>ml -c -Cx -Fl -Zi subprog.asm Microsoft (R) Macro Assembler Version 6.15.8803 Copyright (C) Microsoft Corp 1981-2000. All rights reserved. Assembling: subprog.asm C:\MASM615>link mainprog.obj subprog.obj Microsoft (R) Segmented Executable Linker Version 5.60.339 D Copyright (C) Microsoft Corp 1984-1993. All rights reserved. Run File [mainprog.exe]: List File [nul.map]: Libraries [.lib]: Definitions File [nul.def]: C:\MASM615>mainprog hello world C:\MASM615>
Assembly, compile, linkage • Generally, switches need to be used to specify how to assemble or compile and link. • Sometimes special assemblers or linkers are needed. • To interface with VC++ is straightforward. (See examples from text chapter 12 later in slideshow). Linking to Borland is harder, since 16 and 32 bit turbo assemblers are hard to get hold of and do not come with free compiler distributions. • I have omitted the assembly and linkage for the Borland example which appears next.
Example with arrays in Borland C: the proc model small dataseg newline db 0ah,0dh,'$' codeseg PUBLIC _arrayproc include decout.asm;;;these are just the procs or macros, included in this file include macs.asm _arrayproc proc near push bp mov bp,sp mov ax,[bp+4] call dec_out message newline mov ax,[bp+6] call dec_out message newline mov di,[bp+4] mov cx,[bp+6] looptop: add word ptr [di],10 inc di inc di loop looptop pop bp ret _arrayproc endp end
Example with arrays in Borland C continued: the main #include <stdio.h> extern void arrayproc(int [],int); void main(){ int i,x[20]; //fill array anyhow for(i=0;i<20;i++)x[i]=i*5; arrayproc(x,20); for(i=0;i<20;i++)printf("%d\n",x[i]); }
Running array.c…first two pieces of output were generated in the sub W:\assembly\turboC\BIN>array 65486 20 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105
Another borland c example…using coprocessor extern "C" funct(double); #include <stdio.h> double a,b; void main(){ a=1234.567; funct(a); printf("answer %f",b); }
What does “C” mean? • Cpp compilers use “name mangling” to handle function overloads. Internally, those overloaded functions wind up with names distinguished by their argument lists. • To turn off name mangling, you can ask the compiler to use “C” compiler conventions for compiling functions.
The function .model small .data extrn _b:qword .code public _funct _funct proc near push bp mov bp,sp fld qword ptr [bp+4] fstp _b fwait pop bp ret _funct endp end
Borland example 2, using coprocessor run W:\assembly\turboC\BIN>copro answer 1234.567000
Another coprocessor example • #include "stdio.h" • extern "C" funct(double,double *); • double a,b; • void main(){ • a=1234.567; • funct(a,&b); • printf("answer %f",b); • }
function .model small .code public _funct _funct proc near push bp mov bp,sp fld qword ptr [bp+4] fld qword ptr [bp+4] fadd st,st(1) mov si,[bp+12] fstp qword ptr [si] fwait pop bp ret _funct endp end
Run of copro2 W:\assembly\turboC\BIN>copro2 answer 2469.134000 W:\assembly\turboC\BIN>
An assembly main .model small .stack 100h dataseg val dw ? num dw ? prompt db 'enter',0ah,0dh,'$' p2 db 'value is',0ah,0dh,'$' crlf db 0ah,0dh,'$' include macs.asm codeseg EXTRN _addnums:proc include decin.asm include decout.asm main proc near mov ax, @data mov ds,ax message prompt call dec_in push bx message crlf message prompt call dec_in push bx message crlf call _addnums message p2 call dec_out mov ax,4c00h int 21h main endp end main
The c function • extern "C" int addnums(int,int); • int addnums(int a,int b){ • return a+b;}
run W:\assembly\turboC\BIN>asmtoc enter 123 enter 456 value is 579 W:\assembly\turboC\BIN>
Linking assembly and C • You can use assembly inline • You can link c functions to an assembly main • Or visa versa • Some versions of Borland C are available in the labs • I used the text’s VC++ examples. • As mentioned earlier, you need 32 bit TASM (Borland assembler) to properly configure assembly with borland c programs.
main extern "C" void asm_main(); // asm startup proc void main() { asm_main(); }
Directory listing .586 .MODEL flat,C ; Standard C library functions: system PROTO, pCommand:PTR BYTE printf PROTO, pString:PTR BYTE, args:VARARG scanf PROTO, pFormat:PTR BYTE,pBuffer:PTR BYTE, args:VARARG fopen PROTO, mode:PTR BYTE, filename:PTR BYTE fclose PROTO, pFile:DWORD BUFFER_SIZE = 5000 .data str1 BYTE "cls",0 str2 BYTE "dir/w",0 str3 BYTE "Enter the name of a file: ",0 str4 BYTE "%s",0 str5 BYTE "cannot open file",0dh,0ah,0 str6 BYTE "The file has been opened and closed",0dh,0ah,0 modeStr BYTE "r",0 fileName BYTE 60 DUP(0) pBuf DWORD ? pFile DWORD ?
Asm code part .code asm_main PROC ; clear the screen, display disk directory INVOKE system,ADDR str1 INVOKE system,ADDR str2 ; ask for a filename INVOKE printf,ADDR str3 INVOKE scanf, ADDR str4, ADDR fileName ; try to open the file INVOKE fopen, ADDR fileName, ADDR modeStr mov pFile,eax .IF eax == 0 ; cannot open file? INVOKE printf,ADDR str5 jmp quit .ELSE INVOKE printf,ADDR str6 .ENDIF ; Close the file INVOKE fclose, pFile quit: ret ; return to C++ main asm_main ENDP END
Creating your own obj modules Assemble directory to obj C:\Program Files\Microsoft Visual Studio 8\VC>ML /nologo -Zi -c -Fl -Sg -coff Directory.asm Assembling: Directory.asm Compile DirC.cpp to obj (/c means compile only) C:\Program Files\Microsoft Visual Studio 8\VC>cl /c dirC.cpp Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. dirC.cpp Create the Exe /EHsc is error handling and /Gy enables function linkage C:\Program Files\Microsoft Visual Studio 8\VC>cl /EHsc /Gy dirC.obj directory.obj
public and external • public, in an assembly module, declares that a symbol defined in this module should be made available (by linker) to other modules being linked. • extern indicates that a symbol used in this module is not defined here, but in another module
main.cpp (Borland C) // main.cpp // Calls the external LongRandom function, written in // assembly language, that returns an unsigned 32-bit // random integer. Compile in the Large memory model. #include <iostream.h> extern "C" unsigned long LongRandom(); //"C" indicates to the compiler not to use name mangling but standard C naming //long will return long (32 bit) int in dx:ax const int ARRAY_SIZE = 500; int main() { // Allocate array storage and fill with 32-bit // unsigned random integers. unsigned long * rArray = new unsigned long[ARRAY_SIZE]; for(unsigned i = 0; i < ARRAY_SIZE; i++) { rArray[i] = LongRandom();//call the external (assembly) function cout << rArray[i] << ','; } cout << endl; return 0; }
asm proc longrandom ; LongRandom procedure module (longrand.asm) .model large .386 Public _LongRandom .data seed dd 12345678h//seed should be odd, not even ; Return an unsigned pseudo-random 32-bit integer ; in DX:AX,in the range 0 - FFFFFFFFh. .code _LongRandom proc far, C mov eax, 214013 mul seed xor edx,edx add eax, 2531011 mov seed, eax ; save the seed for the next call shld edx,eax,16 ; copy upper 16 bits of EAX to DX ret _LongRandom endp end
longrand.exe • text examples come with (some) compiled cpp and assembled asm examples. • you would need to find a borland c compiler to undertake this work. • there is a free c compiler (commandline only – no ide) available from inprise (borland) • you would link the two obj files to create an exe
Free compiler from borland • Link for compiler:http://community.borland.com/article/0,1410,20633,00.html
IDE continued& SoftwareDave site • You can “easily” integrate borland C compiler with textpad, also.
(some of the) output C:\MASM615\EXAMPLES\CH12\BORLAN~1\LONGRAND>longrand 3018423131,1530878130,3423460525,3768712380,1536596111,3080048918,405865345,3338 983488,2101941763,875374778,3701378197,761367812,142804919,3419349918,218704873, 3429891848,1470939563,563267010,3913012605,2845790796,1275647967,4244656934,4140 39377,341437136,1709710931,3514126282,2757121893,143223956,2904402183,3569909678 ,1119967161,2589637528,2108869627,1764615890,2858594893,1329724380,2363169583,37 30491702,3727334177,2285801824,3123210915,3454642906,2824439349,1633624100,21641 82615,2533248958,3079939977,2860878888,508074571,3173628898,305623837,3714775404 ,3194643071,781071174,3555499249,887344112,1198979827,3041081834,1769806085,1231 267764,2476963751,402232270,3202784089,3603001528,804990107,2917090546,330242029 ,2403027708,4082347471,1774424406,1769521857,532322944,25218883,2692414714,32352 54229,3377988420,248030455,243485662,2556277545,874473800,4153901803,3773268482, 1644077245,1595142284,7601439,3311657830,3801353361,3514039568,1379067795,117086 3114,2948164261,1899836116,2255181383,4070864878,1071542009,2733667800,147918777 1,555447058,1083903373,2526407196,3437777007,1075325302,658733665,3858822048,177 3814755,145301274,800860533,3897833060,1221102487,228988926,1032703689,159000740 0,587299723,1855199266,1396268637,1587689388,2718803903,2982765446,2479623217,26 26846256,2391008307,164724266,45304901,2099121652,2925348071,2316381198,19766196 73,2389691128,1739136475,246051122,1842254637,1331288380,2072052495,3684733334,3 367158273,1738120384,1832700035,926683450,2192823061,3042687364,1776714295,22092 64670,4182538857,3556774792,3287188523,2616688194,1687137277,1953484,1461674591, 2013705126,2059181009,2093436752,1758589139,1545721930,1913830885,3725474068,363 0252935,394768430,3571828281,3704057880,3017715323,374619986,3690047693,25427375 00,2231748015,1252313526,1122933153,1695323616,3933232419,821810010,3412397237,2 608237732,1359644887,1944395838,3787568649,4049002664,3787889867,4074353762,4137 63997,1536079340,4153486591,811848646,1854782321,2358931568,2978286963,180374794 6,2441068421,2031465524,1969181223,3897558094,2504346073,2239718712,1983074075,7 36157042,3484175981,1094559612,2472450127,795660758,3474915649,3538018048,599589 315,3467666810,2675430997,2041360324,2166136695,4119944286,3507847593,3360816584 ,1743897963,1359133314,4130273085,2096950540,2135623583,2267595750,2322033425,44 5899152,2634365459,985463946,2023903525,2805759828,2587848903,1571956846,3004652 6360559,2991106806,932705761,2555478304,1625201507,3506051226,1167015157,4069063 652,2132818711,3283945854,133102153,1370493928,202900235,1171161506,2383421917,7 6279084, C:\MASM615\EXAMPLES\CH12\BORLAN~1\LONGRAND>
what should c do, what should asm do? • C should do things like i/o and real computations • asm should handle low level operations including graphics--- activities which might involve rom-bios or dos function calls
cpp for read sector example // SectorMain.cpp - Calls ReadSector Procedure #include <iostream.h> #include <conio.h> #include <stdlib.h> const int SECTOR_SIZE = 512; extern "C" ReadSector( char * buffer, long startSector, int driveNum, int numSectors ); void DisplayBuffer( const char * buffer, long startSector, int numSectors ) { int n = 0; long last = startSector + numSectors; for(long sNum = startSector; sNum < last; sNum++) { cout << "\nSector " << sNum << " ---------------------------" << "-----------------------------\n"; for(int i = 0; i < SECTOR_SIZE; i++) { char ch = buffer[n++]; if( unsigned(ch) < 32 || unsigned(ch) > 126) cout << '.'; else cout << ch; } cout << endl; getch(); } }
main.cpp int main() { char * buffer; long startSector; int driveNum; int numSectors; system("CLS"); cout << "Sector display program.\n\n" << "Enter drive number [1=A, 2=B, 3=C, 4=D, 5=E,...]: "; cin >> driveNum; cout << "Starting sector number to read: "; cin >> startSector; cout << "Number of sectors to read: "; cin >> numSectors; buffer = new char[numSectors * SECTOR_SIZE]; cout << "\n\nReading sectors " << startSector << " - " << (startSector + numSectors) << " from Drive " << driveNum << endl; ReadSector( buffer, startSector, driveNum, numSectors ); DisplayBuffer( buffer, startSector, numSectors ); system("CLS"); return 0; }
asm part of reading sectors TITLE Reading Disk Sectors (ReadSec.asm) ; The ReadSector procedure is called from a 16-bit ; Real-mode application written in Borland C++ 5.01. ; It can read FAT12, FAT16, and FAT32 disks under ; MS-DOS, and Windows 95/98/Me. ; Last update: 12/5/01 Public _ReadSector .model small .386 DiskIO STRUC strtSector DD ? ; starting sector number nmSectors DW 1 ; number of sectors bufferOfs DW ? ; buffer offset bufferSeg DW ? ; buffer segment DiskIO ENDS .data diskStruct DiskIO <>
read sectors continued .code ;---------------------------------------------------------- _ReadSector PROC NEAR C ARG bufferPtr:WORD, startSector:DWORD, driveNumber:WORD, \ numSectors:WORD ; ; Read n sectors from a specified disk drive. ; Receives: pointer to buffer that will hold the sector, ; data, starting sector number, drive number, ; and number of sectors. ; Returns: nothing ;---------------------------------------------------------- enter 0,0 pusha mov eax,startSector mov diskStruct.strtSector,eax mov ax,numSectors mov diskStruct.nmSectors,ax mov ax,bufferPtr mov diskStruct.bufferOfs,ax push ds pop diskStruct.bufferSeg mov ax,7305h ; ABSDiskReadWrite mov cx,0FFFFh ; always this value mov dx,driveNumber ; drive number mov bx,OFFSET diskStruct ; sector number mov si,0 ; read mode int 21h ; read disk sector popa leave ret _ReadSector ENDP END
arraysum in C void MySub() { char A = 'A'; int B = 10; char name[20]; name[0] = 'B'; double c = 1.2; } int ArraySum( int array[], int count ) { int sum = 0; for(int i = 0; i < count; i++) sum += array[i]; return sum; } void main() { int Array[50]; int sum = ArraySum( Array, 50 ); }
the array sum.asm showing name mangling • TITLE D:\Kip\AsmBook4\Examples\HLL_Linking\VisualCPP\ArraySum\ArraySum.cpp • .386P • include listing.inc • if @Version gt 510 • .model FLAT • else • _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' • _TEXT ENDS • _DATA SEGMENT DWORD USE32 PUBLIC 'DATA' • _DATA ENDS • CONST SEGMENT DWORD USE32 PUBLIC 'CONST' • CONST ENDS • _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' • _BSS ENDS • _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' • _TLS ENDS • ; COMDAT ?MySub@@YAXXZ • _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' • _TEXT ENDS • ; COMDAT ?ArraySum@@YAHQAHH@Z • _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' • _TEXT ENDS • ; COMDAT _main • _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' • _TEXT ENDS • FLAT GROUP _DATA, CONST, _BSS • ASSUME CS: FLAT, DS: FLAT, SS: FLAT • endif • PUBLIC ?MySub@@YAXXZ ; MySub • EXTRN __fltused:NEAR • ; COMDAT ?MySub@@YAXXZ • _TEXT SEGMENT • ?MySub@@YAXXZ PROC NEAR ; MySub, COMDAT • ; File D:\Kip\AsmBook4\Examples\HLL_Linking\VisualCPP\ArraySum\ArraySum.cpp • ; Line 9 • ret 0 • ?MySub@@YAXXZ ENDP ; MySub • _TEXT ENDS
the array sum.asm showing name mangling PUBLIC ?ArraySum@@YAHQAHH@Z ; ArraySum ; COMDAT ?ArraySum@@YAHQAHH@Z _TEXT SEGMENT _array$ = 8 _count$ = 12 ?ArraySum@@YAHQAHH@Z PROC NEAR ; ArraySum, COMDAT ; Line 16 mov edx, DWORD PTR _count$[esp-4] xor eax, eax test edx, edx jle SHORT $L279 mov ecx, DWORD PTR _array$[esp-4] push esi $L277: ; Line 17 mov esi, DWORD PTR [ecx] add ecx, 4 add eax, esi dec edx jne SHORT $L277 pop esi $L279: ; Line 20 ret 0 ?ArraySum@@YAHQAHH@Z ENDP ; ArraySum _TEXT ENDS PUBLIC _main ; COMDAT _main _TEXT SEGMENT _Array$ = -200 _main PROC NEAR ; COMDAT ; Line 24 sub esp, 200 ; 000000c8H ; Line 27 lea eax, DWORD PTR _Array$[esp+200] push 50 ; 00000032H push eax call ?ArraySum@@YAHQAHH@Z ; ArraySum ; Line 30 add esp, 208 ; 000000d0H ret 0 _main ENDP _TEXT ENDS END
in line asm example • #pragma warning (disable:4101) • // disable warning about unreferenced local variables • #include <iostream> • int main() • { • std::cout << "(this program generates no output)\n\n"; • struct Package { • long originZip; // 4 • long destinationZip; // 4 • float shippingPrice; // 4 • }; • char myChar; • bool myBool; • short myShort; • int myInt; • long myLong; • float myFloat; • double myDouble; • Package myPackage; • long double myLongDouble; • long myLongArray[10];
inline example continued __asm { mov eax,myPackage.destinationZip; mov eax,LENGTH myInt; // 1 mov eax,LENGTH myLongArray; // 10 mov eax,TYPE myChar; // 1 mov eax,TYPE myBool; // 1 mov eax,TYPE myShort; // 2 mov eax,TYPE myInt; // 4 mov eax,TYPE myLong; // 4 mov eax,TYPE myFloat; // 4 mov eax,TYPE myDouble; // 8 mov eax,TYPE myPackage; // 12 mov eax,TYPE myLongDouble; // 8 mov eax,TYPE myLongArray; // 4 mov eax,SIZE myLong; // 4 mov eax,SIZE myPackage; // 12 mov eax,SIZE myLongArray; // 40 } return 0; }