How can adding a function call cause other symbols to become undefined when linking?-Collection of common programming errors
I’m hoping someone will be able to help troubleshoot what I think is a linker script issue.
I’m encountering a strange problem after adding a call to a new function. Without the function call, my object files link correctly, however, with the new function call added, I get an undefined reference to a symbol from another object file (I’ve verified it is actually present using objdump).
Also strangely, with the function call present, if I link all object files first using ld -r (to give a relocatable output) and then using my link script, there are no undefined references, but it seems the link script is being ignored since the output binary does not have the correct entry point.
My (cross-compiler) ld version:
> i586-elf-ld –version
GNU ld (GNU Binutils) 2.20.1.20100303
My attempts at proving that the ‘missing’ symbol is present:
> i586-elf-ld -T link.ld -o kernel32.bin kernel_loader.o main.o stdio.o common.o gdt.o gdt.bin -y putch
main.o: reference to putch stdio.o: definition of putch main.o: In function `main': main.c:(.text+0x1f): undefined reference to `putch'
N.B. (when I produced this output, I was using a filename of gdt.bin for nasm compiled assembler, it is just another .o file, really)
I can see the symbol that is ‘missing’ in the appropriate object file:
> i586-elf-objdump -ht stdio.o
stdio.o: file format elf32-i386Sections: Idx Name Size VMA LMA File off Algn 0 .text 000002f9 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 0000000c 00000000 00000000 00000330 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000008 00000000 00000000 0000033c 2**2 ALLOC 3 .comment 00000012 00000000 00000000 0000033c 2**0 CONTENTS, READONLY SYMBOL TABLE: 00000000 l df *ABS* 00000000 stdio.c 00000000 l d .text 00000000 .text 00000000 l d .data 00000000 .data 00000000 l d .bss 00000000 .bss 00000000 l d .comment 00000000 .comment 00000000 g F .text 00000016 strlen 00000016 g F .text 0000005c scroll 00000008 g O .data 00000004 numrows 00000004 g O .bss 00000004 ypos 00000004 g O .data 00000004 numcols 00000004 O *COM* 00000004 screen_mem 00000000 *UND* 00000000 memcpy 00000000 *UND* 00000000 memsetw 00000072 g F .text 0000007d newline 00000000 g O .bss 00000004 xpos 000000ef g F .text 0000002e writech 00000000 g O .data 00000004 colour 0000011d g F .text 00000061 cls 0000017e g F .text 00000010 init_video 0000018e g F .text 00000133 putch 000002c1 g F .text 00000037 puts 000002f8 g F .text 00000001 set_text_colour
And the object file with unresolved reference:
> i586-elf-objdump -ht main.o
main.o: file format elf32-i386 Sections: Idx Name Size VMA LMA File off Algn 0 .text 0000007f 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 00000000 00000000 00000000 000000b4 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000000 00000000 00000000 000000b4 2**2 ALLOC 3 .rodata.str1.1 00000024 00000000 00000000 000000b4 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .comment 00000012 00000000 00000000 000000d8 2**0 CONTENTS, READONLY SYMBOL TABLE: 00000000 l df *ABS* 00000000 main.c 00000000 l d .text 00000000 .text 00000000 l d .data 00000000 .data 00000000 l d .bss 00000000 .bss 00000000 l d .rodata.str1.1 00000000 .rodata.str1.1 00000000 l d .comment 00000000 .comment 00000000 g F .text 0000007f main 00000000 *UND* 00000000 init_video 00000000 *UND* 00000000 gdt_install 00000000 *UND* 00000000 putch 00000000 *UND* 00000000 puts 00000018 O *COM* 00000001 gdt 00000006 O *COM* 00000001 gdtp
My link script (not sure if it’s going to be relevant):
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
.text phys : AT(phys) {
code = .;
*(.text)
*(.rodata*)
. = ALIGN(4096);
}
.data . : AT(data)
{
data = .;
*(.data)
. = ALIGN(4096);
}
.bss . : AT(bss)
{
bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .;
}
If I comment out the call to putch in main.c, I instead get undefined references to puts… if I remove the call to gdt_install, no errors!
gdt_install is in the C file, but gdt_install calls a function which is defined in gdt.asm.
void gdt_install() {
/* ... */
gdt_reset();
}
[bits 32]
[section .text]
global gdt_reset
extern gdtp
gdt_reset:
lgdt [gdtp]
mov ax, 0x10 ; 0x10 offset for data segment (sizeof(struct gdt_entry) * 2)
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:gdt_reset2 ; 0x08 offset for code segment (sizeof(struct gdt_entry))
gdt_reset2:
ret ; ret back to C
To try and further diagnose the cause, I’ve been playing around trying to recreate the errors. If I move the gdt_install() function call to a specific place in the source code, I don’t receive any errors and everything works fine:
int main() {
init_video();
putch('A');
puts("
Originally posted 2013-11-09 22:56:02.