Linker Error when initializing arrays

Programming, for all ages and all languages.
Post Reply
rob
Posts: 7
Joined: Thu Apr 30, 2009 10:24 am

Linker Error when initializing arrays

Post by rob »

I'm having trouble getting my OS off the ground. I originally started writing it in assembly, but decided to give C a go. However, I have been trying to get C to work with arrays (in hopes to make printing strings easier) with little luck. I can initialize an array like this:

Code: Select all

char string[3];
string[0] = 'h';
string[1] = 'i';
string[2] = '\0';
The system boots and displays that string perfectly. However, I get linker errors when I try this:

Code: Select all

char string[] = "hello";
The program compiles fine, but the linker (JLoc) gives me this message:
"Undefined symbol SCOPY@ in main.c <main.o>"

I'm attaching a zip file with my code and the compiler/linker/scripts for making all of this work. Does anyone know how to solve this problem? I am using nasm, Borland Turbo C 2.01, and JLoc.

-Thanks
Attachments
systest.zip
A zip file with my test source code and the compile/link scripts. I wasn't able to keep the compiler and linker in the file, but it will work if you add a directory called "tools" inside of the main folder that contains the files "tcc" (the compiler), "jloc" (the linker), and "nasm" (the assembler)
(3.34 KiB) Downloaded 164 times
skyking
Member
Member
Posts: 174
Joined: Sun Jan 06, 2008 8:41 am

Re: Linker Error when initializing arrays

Post by skyking »

Judging from the first sample it looks like the string is declared within a function. Depending on the compiler this may result in the space for the string is allocated on the stack and initialized by copying the contents of the string literal to the string (char array).

I'd suggest that you either declare the strings as static variables (at file scope or function scope), or declare string as a char pointer:

Code: Select all

static char string1[] = "String1";

void fubar()
{
  static char string2[] = "String2";
  char const* string3 = "String3";
}
At least one of these will avoid the undefined symbol, if not you have to investigate what the required symbol is and define it properly...
DeletedAccount
Member
Member
Posts: 566
Joined: Tue Jun 20, 2006 9:17 am

Re: Linker Error when initializing arrays

Post by DeletedAccount »

Hi,
Hmmm ... very interesting , running with tcc -S i get

Code: Select all


	ifndef	??version
?debug	macro
	endm
$comm	macro	name,dist,size,count
	comm	dist name:BYTE:count*size
	endm
	else
$comm	macro	name,dist,size,count
	comm	dist name[size]:BYTE:count
	endm
	endif
	?debug	S "main.c"
	?debug	C E9B6719E3A066D61696E2E63
	?debug	C E950719E3A11696E636C756465732F737464696E632E68
_TEXT	segment byte public 'CODE'
_TEXT	ends
DGROUP	group	_DATA,_BSS
	assume	cs:_TEXT,ds:DGROUP
_DATA	segment word public 'DATA'
d@	label	byte
d@w	label	word
_DATA	ends
_BSS	segment word public 'BSS'
b@	label	byte
b@w	label	word
_BSS	ends
_TEXT	segment byte public 'CODE'
   ;	
   ;	void printString(char *ptr) 
   ;	
	assume	cs:_TEXT
_printString	proc	near
	push	bp
	mov	bp,sp
	push	si
   ;	
   ;	{
   ;	  int i;
   ;	  for(i=0;i<80;i++) 
   ;	
	xor	si,si
	jmp	short @1@146
@1@50:
   ;	
   ;	  {
   ;		  if (ptr[i] != '\0')
   ;	
	mov	bx,word ptr [bp+4]
	cmp	byte ptr [bx+si],0
	je	short @1@98
   ;	
   ;		  {
   ;			  putc(ptr[i]);
   ;	
	mov	bx,word ptr [bp+4]
	mov	al,byte ptr [bx+si]
	cbw	
	push	ax
	call	near ptr _putc
	pop	cx
   ;	
   ;		  } else {
   ;	
	jmp	short @1@122
@1@98:
   ;	
   ;			  i = 80;
   ;	
	mov	si,80
@1@122:
	inc	si
@1@146:
	cmp	si,80
	jl	short @1@50
   ;	
   ;		  }
   ;	  }
   ;	}
   ;	
	pop	si
	pop	bp
	ret	
_printString	endp
_TEXT	ends
_DATA	segment word public 'DATA'
	db	104
	db	101
	db	108
	db	108
	db	111
	db	0
_DATA	ends
_TEXT	segment byte public 'CODE'
   ;	
   ;	int main(void) 
   ;	
	assume	cs:_TEXT
_main	proc	near
	push	bp
	mov	bp,sp
	sub	sp,6
	push	ss
	lea	ax,word ptr [bp-6]
	push	ax
	push	ds
	mov	ax,offset DGROUP:d@+0
	push	ax
	mov	cx,6
	call	near ptr N_SCOPY@
   ;	
   ;	{
   ;	    /*Setting up a string this way (with the double quotes or
   ;	    array initialization will cause a linker error.*/
   ;		char string[] = "hello";
   ;		
   ;		/*Setting up a string this way will work.*/
   ;	    /*char string[80];
   ;		string[0] = 'h';
   ;		string[1] = 'i';
   ;		string[2] = '\0';*/
   ;		
   ;		/*Print a string.*/
   ;		printString(string);
   ;	
	lea	ax,word ptr [bp-6]
	push	ax
	call	near ptr _printString
	pop	cx
   ;	
   ;		pause();
   ;	
	call	near ptr _pause
   ;	
   ;		return 0;
   ;	
	xor	ax,ax
	jmp	short @2@50
@2@50:
   ;	
   ;	}
   ;	
	mov	sp,bp
	pop	bp
	ret	
_main	endp
	?debug	C E9
_TEXT	ends
_DATA	segment word public 'DATA'
s@	label	byte
_DATA	ends
_TEXT	segment byte public 'CODE'
_TEXT	ends
	extrn	_pause:near
	extrn	_putc:near
	public	_main
	extrn	N_SCOPY@:far
	public	_printString
	end

Clearly N_SCOPY is a call generated by the compiler to some internal library function , not available in a kernel , I think there a is a compiler switch to make sure that no call to internal library functions happens, but I do not remember it now :mrgreen: ., However use

Code: Select all

char *string  = "Hello" ;
instead of 
char string[] = "Hello";
for constant strings , this should fix the problem . I am a moron and I might be wrong , you may or may not take this seriously

Regards
Shrek
rob
Posts: 7
Joined: Thu Apr 30, 2009 10:24 am

Re: Linker Error when initializing arrays

Post by rob »

So after a little poking around, I found out that by adding 256 to the "ptr" variable (see new "main.c" file included with this post), my text "magically" gets printed. However, it only works when running under Windows and won't work when I try to boot my OS. Can anyone explain either of these phenomena?
Attachments
main.c
(257 Bytes) Downloaded 99 times
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Linker Error when initializing arrays

Post by Combuster »

Under windows, your code gets executed as an old .COM file - which means 256 bytes of retroness are prepended to the binary containing the commandline and such. At boot time, your code is most likely loaded at 0x0000:0x7c00, which means the code thinks there are almost 32K data before the bootloader.

Change CS/DS/ES/SS to make all addresses relative to zero. (in the bootloader case, load them with 0x7c0, in the .com case, add 16 to each)

I see you are using JLoc - which is very advanced. I expect that you should be able to set an offset somewhere (so that it automatically adds a certain offset to all addresses)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply