Page 1 of 1
Linker Error when initializing arrays
Posted: Thu Apr 30, 2009 1:23 pm
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:
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
Re: Linker Error when initializing arrays
Posted: Thu Apr 30, 2009 2:04 pm
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...
Re: Linker Error when initializing arrays
Posted: Thu Apr 30, 2009 5:34 pm
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
., 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
Re: Linker Error when initializing arrays
Posted: Sun Aug 23, 2009 1:47 pm
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?
Re: Linker Error when initializing arrays
Posted: Sun Aug 23, 2009 1:53 pm
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)