Subj : Re: Error in linking .cpp with Borland 4.52 To : borland.public.cpp.borlandcpp From : James Kim Date : Wed Jul 23 2003 10:27 am Thanks Ed for your help. I, however, was not successful in linking. The following is the result: C:\BC45\BIN>tlink /m/v/s/c c0l test main,my_main,,cl Turbo Link Version 7.00 Copyright (c) 1987, 1994 Borland International Error: Undefined symbol _main in module c0.asm As a matter of fact, I have my own startup code and I have tried linking with it before. The result was same > Error: Undefined symbol operator new(unsigned int) in module I know that it can not be this much difficult just to complie and link a very simple program. I am guessing that there is something that I am doing wrong. I'd like to provide you more detail information regarding my environment. Would you please please help me? * I pasted all my files at the bottom of this email 1) I have Borland 4.52 installed in my C drive ==> C:\BC45\ 2) I have my startup code named 'startup.obj' in C:\BC\45\BIN 'startup.asm' is located in C:\BC45\BIN\Chapter3 I am 99.99% sure that the startup code is okay.(I could tlink with C source files). 3) I have two source files: led.cpp & blink.cpp led.cpp: constructor and one public function with no contents blink.cpp: main function with no contents but '#include "led.h" Compiling/linking works perfectly fine with all the source files implemented in C instead of C++. I am guessing that the reason for error has to do with linking C++ source files! The following is the linking error message: C:\BC45\BIN>tlink /m /v /s /c startup led blink, blink.exe, blink.map Turbo Link Version 7.00 Copyright (c) 1987, 1994 Borland International Error: Undefined symbol _main in module chapter3\startup.asm Error: Undefined symbol operator new(unsigned int) in module led.cpp I'd really appreciate it if you'd help me on this. Thank you so much. James ------------------------------------------------------------------------------------------------------------------------ "Ed Mulroy [TeamB]" wrote: The error told you part of what is wrong. The linker was not told to use the compiler's runtime library or the compiler's startup code. Instead of this tlink /m /v /s /c test.obj main.obj, my_main.exe, my_main.map try this: tlink /m/v/s/c c0l test main,my_main,,cl Where the '0' in c0l is a zero, not the letter 'o'. . Ed ------------------------------------------------------------------------------------------------------------------------ 1) blink.cpp /*************************************************************************** * * Filename: blink.c * **********************************************************************/ #include "led.h" /********************************************************************** * * Function: main() * * Description: Blink the green LED once a second. * **********************************************************************/ void main(void) { } /* main() */ ----------------------------------------------------------------------------------------------------------------------- 2) led.cpp /********************************************************************** * * Filename: led.cpp * **********************************************************************/ #include "led.h" /********************************************************************** * * Function: constructor() * * Description: Toggle the state of one or both LED's. * **********************************************************************/ led::led() { // To be implemented } /* constructor */ /********************************************************************** * * Function: toggleLed() * * Description: Toggle the state of one or both LED's. * **********************************************************************/ void led::toggleLed(void) { // To be implemented } /* toggleLed() */ ----------------------------------------------------------------------------------------------------------------------- 3) led.h /********************************************************************** * * Filename: led.h * **********************************************************************/ #ifndef _LED_H #define _LED_H class led { public: led(); void toggleLed(void); }; #endif /* _LED_H */ ----------------------------------------------------------------------------------------------------------------------- 3) startup.asm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Filename: startup.asm ; ; Description: Startup code for Borland C/C++. ; ; Notes: This module should be specified first during linking. ; ; Warnings: The order of the segments within this file matters. ; ; ; Copyright (c) 1998 by Michael Barr. This software is placed into ; the public domain and may be used for any purpose. However, this ; notice must not be changed or removed and no warranty is either ; expressed or implied by its publication or distribution. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NAME startup ; ; Global Variables ; PUBLIC _errno ; Required by the Borland libraries. PUBLIC __psp ; Required for dynamic memory allocation. PUBLIC __brklvl ; Required for dynamic memory allocation. PUBLIC __heapbase ; Required for dynamic memory allocation. PUBLIC __heaptop ; Required for dynamic memory allocation. ; ; Functions Defined Externally ; EXTRN _main : FAR ; ; Constants ; stack_size EQU 1024 ; By default, create a 1-kbyte stack. ram_size EQU 2000h ; The Arcom board has 2000h pages of RAM. PCB EQU 0ff00h ; Base of the Peripheral Control Block. GCS0ST EQU PCB + 80h ; General-purpose chip select 0 start. GCS0SP EQU PCB + 82h ; General-purpose chip select 0 stop. GCS1ST EQU PCB + 84h ; General-purpose chip select 1 start. GCS1SP EQU PCB + 86h ; General-purpose chip select 1 stop. ; ; Initializer/Terminator Structure Format (used by C++ modules) ; Initializer STRUC ctype DB ? ; Code Segment Type (0 = near, 1 = far) priority DB ? ; Priority (0 = highest, 0xff = lowest) foffset DW ? ; Function Pointer (Offset) fsegment DW ? ; Function Pointer (Segment) Initializer ENDS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Segment: _text ; ; Description: The following segment contains the startup code. ; ; Notes: If desired, this segment can be located in ROM. ; ; Warnings: The terminators are not executed, since embedded ; applications are not expected to complete and exit. ; However, an _exit_ segment must still be declared ; here, for compatibility with existing C++ libraries. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _text SEGMENT PARA PUBLIC 'CODE' ASSUME CS:_text _startup PROC FAR ; ; Disable interrupts and set the direction flag. ; cli cld ; ; Perform hardware initializations that may not have been ; done by the hardware initialization code in EEPROM. ; mov dx, GCS0ST mov ax, 7000h out dx, ax mov dx, GCS0SP mov ax, 710Ah out dx, ax mov dx, GCS1ST mov ax, 7100h out dx, ax mov dx, GCS1SP mov ax, 720Ah out dx, ax ; ; Initialize the segment registers. ; mov ax, dgroup mov ds, ax mov es, ax ASSUME ds:dgroup, es:dgroup initData: ; ; Zero the uninitialized data segment. ; xor ax, ax mov di, offset dgroup:bss_start mov cx, offset dgroup:data_end sub cx, di shr cx, 1 jcxz initStack rep stosw initStack: ; ; Initialize the stack. ; mov ax, _stack mov ss, ax mov sp, offset stack_top ASSUME ss:_stack initHeap: ; ; Initialize the heap. ; mov ax, _farheap ; heapBase inc ax mov [__brklvl + 2], ax mov [__brklvl], 0000h mov [__heapbase + 2], ax mov [__heapbase], 0000h mov [__psp], ax mov bx, ram_size ; heapEnd mov [__heaptop + 2], bx mov [__heaptop], 0000h mov dx, _farheap mov ds, dx ASSUME ds:_farheap mov [id], 'Z' mov [owner], 0 sub bx, ax mov [npages], bx initModules: ; ; Call any static initializers found in the _init_ segment. ; The C++ language guarantees that these functions are called ; before main(). ; ; The following registers are used. ; SI - offset of the next initializer ; DI - offset of the last initializer ; CX - number of initializers remaining ; BX - current initializer ; AH - current priority ; mov si, offset igroup:init_start mov di, offset igroup:init_end mov ax, dgroup mov ds, ax mov ax, igroup mov es, ax ASSUME ds:dgroup, es:nothing mov ax, di sub ax, si sub dx, dx mov cx, SIZE Initializer idiv cx mov cx, ax ; CX has total number of initializers. jcxz callMain sub ah, ah ; AH has current priority (start at 0). firstInitializer: mov bx, si ; Restart, from the top of the table. nextInitializer: cmp bx, di ; Are there initializers left to check? jae nextPriority ; If not, try the next priority. cmp es:[bx.priority], ah ; Check this initializer's priority. jne tryNextInitializer ; If it's not a match, try the next. push es push ax push bx push cx push si push di call dword ptr es:[bx.foffset] ; Call the initializer pop di pop si pop cx pop bx pop ax pop es dec cx ; Decrement number of initializers. jz callMain ; If zero left, continue. tryNextInitializer: add bx, SIZE Initializer jmp nextInitializer nextPriority: inc ah ; Process the next priority. jmp firstInitializer callMain: ; ; Enable interrupts and transfer control to C/C++. ; sti call _main ; ; A return from main() is unexpected. Halt the processor. ; hlt _startup endp _text ENDS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Segments: _init_, _initend_, _exit_, _exitend_ ; ; Description: The following segments are used for C++ initializers ; and terminators. ; ; Notes: If possible, these segments should be located in ROM. ; ; Warnings: The terminators are not executed, since embedded ; applications are not expected to complete and exit. ; However, an _exit_ segment must still be declared ; here, for compatibility with existing libraries. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _init_ SEGMENT PARA PUBLIC 'INITDATA' init_start LABEL DWORD _init_ ENDS igroup GROUP _init_ _initend_ SEGMENT BYTE PUBLIC 'INITDATA' init_end LABEL DWORD _initend_ ENDS igroup GROUP _initend_ _exit_ SEGMENT DWORD PUBLIC 'EXITDATA' exit_start LABEL DWORD _exit_ ENDS igroup GROUP _exit_ _exitend_ SEGMENT BYTE PUBLIC 'EXITDATA' exit_end LABEL DWORD DB 16 DUP (?) ; Force the next segment to a new paragraph _exitend_ ENDS igroup GROUP _exitend_ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Segments: _data, _bss, _bssend, _stack, _farheap ; ; Description: The following segments are used for the initialized ; and uninitialized data, stack, and heap, respectively. ; ; Notes: These segments must be located in RAM. In fact, the ; _farheap segment will contain whatever RAM is left over ; after the others are allocated space. ; ; Warnings: For compatibility with Borland C/C++, the order of ; these segments must not be changed. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _data SEGMENT PARA PUBLIC 'DATA' data_start LABEL BYTE ; Mark the start of the initialized data. _data ENDS dgroup GROUP _data _bss SEGMENT WORD PUBLIC 'BSS' bss_start LABEL BYTE ; Mark the start of the uninitialized data. _errno DW ? __psp DW ? __brklvl DW ? DW ? __heapbase DW ? DW ? __heaptop DW ? DW ? _bss ENDS dgroup GROUP _bss _bssend SEGMENT WORD PUBLIC 'BSSEND' DW ? ; Give a fixed size for proper alignment. data_end LABEL WORD ; Mark the end of the uninitialized data. _bssend ENDS dgroup GROUP _bssend _stack SEGMENT PARA STACK 'STACK' DB stack_size DUP (?) ; Reserve space for the stack. EVEN stack_top DW ? _stack ENDS _farheap SEGMENT PARA PUBLIC 'FARHEAP' id DB ? owner DW ? npages DW ? DB 11 DUP (?) ; Round the segment up to a full page. _farheap ENDS END _startup ; End module and declare _startup as entry point. ----------------------------------------------------------------------------------------------------------------------- .