(1) This is the main function (runproctest.c):
#include "defs.h" void runproctest(void) { cprintf("testing runnable: test1n"); }
(2) defs.h:
// console.c void cprintf(char*, ...);
(3) console.c
#include "defs.h" void cprintf(char *fmt, ...) { int i, c, locking; uint *argp; char *s; locking = cons.locking; if(locking) acquire(&cons.lock); if (fmt == 0) ... }
(4) main.c
#include "types.h" #include "defs.h" #include "param.h" #include "memlayout.h" #include "mmu.h" #include "proc.h" #include "x86.h" static void startothers(void); static void mpmain(void) __attribute__((noreturn)); extern pde_t *kpgdir; extern char end[]; // first address after kernel loaded from ELF file // Bootstrap processor starts running C code here. // Allocate a real stack and switch to it, first // doing some setup required for memory allocator to work. int main(void) { kinit1(end, P2V(4*1024*1024)); // phys page allocator kvmalloc(); // kernel page table mpinit(); // detect other processors lapicinit(); // interrupt controller seginit(); // segment descriptors cprintf("ncpu%d: starting xv6nn", cpunum()); picinit(); // another interrupt controller ioapicinit(); // another interrupt controller consoleinit(); // console hardware uartinit(); // serial port pinit(); // process table tvinit(); // trap vectors binit(); // buffer cache fileinit(); // file table ideinit(); // disk if(!ismp) timerinit(); // uniprocessor timer startothers(); // start other processors kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers() userinit(); // first user process mpmain(); // finish this processor's setup } // Other CPUs jump here from entryother.S. static void mpenter(void) { switchkvm(); seginit(); lapicinit(); mpmain(); } // Common CPU setup code. static void mpmain(void) { cprintf("cpu%d: startingn", cpunum()); idtinit(); // load idt register xchg(&cpu->started, 1); // tell startothers() we're up scheduler(); // start running processes } pde_t entrypgdir[]; // For entry.S // Start the non-boot (AP) processors. static void startothers(void) { extern uchar _binary_entryother_start[], _binary_entryother_size[]; uchar *code; struct cpu *c; char *stack; // Write entry code to unused memory at 0x7000. // The linker has placed the image of entryother.S in // _binary_entryother_start. code = P2V(0x7000); memmove(code, _binary_entryother_start, (uint)_binary_entryother_size); for(c = cpus; c < cpus+ncpu; c++){ if(c == cpus+cpunum()) // We've started already. continue; // Tell entryother.S what stack to use, where to enter, and what // pgdir to use. We cannot use kpgdir yet, because the AP processor // is running in low memory, so we use entrypgdir for the APs too. stack = kalloc(); *(void**)(code-4) = stack + KSTACKSIZE; *(void**)(code-8) = mpenter; *(int**)(code-12) = (void *) V2P(entrypgdir); lapicstartap(c->apicid, V2P(code)); // wait for cpu to finish mpmain() while(c->started == 0) ; } } // The boot page table used in entry.S and entryother.S. // Page directories (and page tables) must start on page boundaries, // hence the __aligned__ attribute. // PTE_PS in a page directory entry enables 4Mbyte pages. __attribute__((__aligned__(PGSIZE))) pde_t entrypgdir[NPDENTRIES] = { // Map VA's [0, 4MB) to PA's [0, 4MB) [0] = (0) | PTE_P | PTE_W | PTE_PS, // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS, };
(5) Here is my Makefile:
OBJS = bio.o console.o exec.o file.o fs.o ide.o ioapic.o kalloc.o kbd.o lapic.o log.o main.o mp.o picirq.o pipe.o proc.o spinlock.o string.o swtch.o syscall.o sysfile.o sysproc.o timer.o trapasm.o trap.o uart.o vectors.o vm.o runproctest.o # Cross-compiling (e.g., on Mac OS X) # TOOLPREFIX = i386-jos-elf # Using native tools (e.g., on X86 Linux) #TOOLPREFIX = # Try to infer the correct TOOLPREFIX if not set ifndef TOOLPREFIX TOOLPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; then echo 'i386-jos-elf-'; elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; then echo ''; else echo "***" 1>&2; echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; echo "*** prefix other than 'i386-jos-elf-', set your TOOLPREFIX" 1>&2; echo "*** environment variable to that prefix and run 'make' again." 1>&2; echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; echo "***" 1>&2; exit 1; fi) endif # If the makefile can't find QEMU, specify its path here QEMU = /home/yuanzheng/Qemu_installed/bin/qemu-system-i386 # Try to infer the correct QEMU ifndef QEMU QEMU = $(shell if which qemu > /dev/null; then echo qemu; exit; elif which qemu-system-i386 > /dev/null; then echo qemu-system-i386; exit; else qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; if test -x $$qemu; then echo $$qemu; exit; fi; fi; echo "***" 1>&2; echo "*** Error: Couldn't find a working QEMU executable." 1>&2; echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; echo "*** or have you tried setting the QEMU variable in Makefile?" 1>&2; echo "***" 1>&2; exit 1) endif CC = $(TOOLPREFIX)gcc AS = $(TOOLPREFIX)gas LD = $(TOOLPREFIX)ld OBJCOPY = $(TOOLPREFIX)objcopy OBJDUMP = $(TOOLPREFIX)objdump CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer #CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -fvar-tracking -fvar-tracking-assignments -O0 -g -Wall -MD -gdwarf-2 -m32 -Werror -fno-omit-frame-pointer CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) ASFLAGS = -m32 -gdwarf-2 -Wa,-divide # FreeBSD ld wants ``elf_i386_fbsd'' LDFLAGS += -m $(shell $(LD) -V | grep elf_i386 2>/dev/null) xv6.img: bootblock kernel fs.img dd if=/dev/zero of=xv6.img count=10000 dd if=bootblock of=xv6.img conv=notrunc dd if=kernel of=xv6.img seek=1 conv=notrunc xv6memfs.img: bootblock kernelmemfs dd if=/dev/zero of=xv6memfs.img count=10000 dd if=bootblock of=xv6memfs.img conv=notrunc dd if=kernelmemfs of=xv6memfs.img seek=1 conv=notrunc bootblock: bootasm.S bootmain.c $(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c $(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S $(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o $(OBJDUMP) -S bootblock.o > bootblock.asm $(OBJCOPY) -S -O binary -j .text bootblock.o bootblock ./sign.pl bootblock entryother: entryother.S $(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c entryother.S $(LD) $(LDFLAGS) -N -e start -Ttext 0x7000 -o bootblockother.o entryother.o $(OBJCOPY) -S -O binary -j .text bootblockother.o entryother $(OBJDUMP) -S bootblockother.o > entryother.asm initcode: initcode.S $(CC) $(CFLAGS) -nostdinc -I. -c initcode.S $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o $(OBJCOPY) -S -O binary initcode.out initcode $(OBJDUMP) -S initcode.o > initcode.asm kernel: $(OBJS) entry.o entryother initcode kernel.ld $(LD) $(LDFLAGS) -T kernel.ld -o kernel entry.o $(OBJS) -b binary initcode entryother $(OBJDUMP) -S kernel > kernel.asm $(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym # kernelmemfs is a copy of kernel that maintains the # disk image in memory instead of writing to a disk. # This is not so useful for testing persistent storage or # exploring disk buffering implementations, but it is # great for testing the kernel on real hardware without # needing a scratch disk. MEMFSOBJS = $(filter-out ide.o,$(OBJS)) memide.o kernelmemfs: $(MEMFSOBJS) entry.o entryother initcode kernel.ld fs.img $(LD) $(LDFLAGS) -T kernel.ld -o kernelmemfs entry.o $(MEMFSOBJS) -b binary initcode entryother fs.img $(OBJDUMP) -S kernelmemfs > kernelmemfs.asm $(OBJDUMP) -t kernelmemfs | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernelmemfs.sym tags: $(OBJS) entryother.S _init etags *.S *.c vectors.S: vectors.pl perl vectors.pl > vectors.S ULIB = ulib.o usys.o printf.o umalloc.o _%: %.o $(ULIB) $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^ $(OBJDUMP) -S $@ > $*.asm $(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym _forktest: forktest.o $(ULIB) # forktest has less library code linked in - needs to be small # in order to be able to max out the proc table. $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o _forktest forktest.o ulib.o usys.o $(OBJDUMP) -S _forktest > forktest.asm mkfs: mkfs.c fs.h gcc -Werror -Wall -o mkfs mkfs.c # Prevent deletion of intermediate files, e.g. cat.o, after first build, so # that disk image changes after first build are persistent until clean. More # details: # http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html .PRECIOUS: %.o UPROGS= _cat _echo _forktest _grep _init _kill _ln _ls _mkdir _rm _sh _stressfs _usertests _wc _zombie _runnable _runnabletest _runproctest fs.img: mkfs README $(UPROGS) ./mkfs fs.img README $(UPROGS) -include *.d clean: rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg *.o *.d *.asm *.sym vectors.S bootblock entryother initcode initcode.out kernel xv6.img fs.img kernelmemfs mkfs .gdbinit $(UPROGS) # make a printout FILES = $(shell grep -v '^#' runoff.list) PRINT = runoff.list runoff.spec README toc.hdr toc.ftr $(FILES) xv6.pdf: $(PRINT) ./runoff ls -l xv6.pdf print: xv6.pdf # run in emulators bochs : fs.img xv6.img if [ ! -e .bochsrc ]; then ln -s dot-bochsrc .bochsrc; fi bochs -q # try to generate a unique GDB port GDBPORT = $(shell expr `id -u` % 5000 + 25000) # QEMU's gdb stub command line changed in 0.11 QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; then echo "-gdb tcp::$(GDBPORT)"; else echo "-s -p $(GDBPORT)"; fi) ifndef CPUS CPUS := 2 endif QEMUOPTS = -drive file=fs.img,index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA) qemu: fs.img xv6.img $(QEMU) -serial mon:stdio $(QEMUOPTS) qemu-memfs: xv6memfs.img $(QEMU) -drive file=xv6memfs.img,index=0,media=disk,format=raw -smp $(CPUS) -m 256 qemu-nox: fs.img xv6.img $(QEMU) -nographic $(QEMUOPTS) .gdbinit: .gdbinit.tmpl sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@ qemu-gdb: fs.img xv6.img .gdbinit @echo "*** Now run 'gdb'." 1>&2 $(QEMU) -serial mon:stdio $(QEMUOPTS) -S $(QEMUGDB) qemu-nox-gdb: fs.img xv6.img .gdbinit @echo "*** Now run 'gdb'." 1>&2 $(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB) # CUT HERE # prepare dist for students # after running make dist, probably want to # rename it to rev0 or rev1 or so on and then # check in that version. EXTRA= mkfs.c ulib.c user.h cat.c echo.c forktest.c grep.c kill.c ln.c ls.c mkdir.c rm.c stressfs.c usertests.c wc.c zombie.c printf.c umalloc.c runnable.c printf.h runnabletest.c runproctest.c README dot-bochsrc *.pl toc.* runoff runoff1 runoff.list .gdbinit.tmpl gdbutil dist: rm -rf dist mkdir dist for i in $(FILES); do grep -v PAGEBREAK $$i >dist/$$i; done sed '/CUT HERE/,$$d' Makefile >dist/Makefile echo >dist/runoff.spec cp $(EXTRA) dist dist-test: rm -rf dist make dist rm -rf dist-test mkdir dist-test cp dist/* dist-test cd dist-test; $(MAKE) print cd dist-test; $(MAKE) bochs || true cd dist-test; $(MAKE) qemu # update this rule (change rev#) when it is time to # make a new revision. tar: rm -rf /tmp/xv6 mkdir -p /tmp/xv6 cp dist/* dist/.gdbinit.tmpl /tmp/xv6 (cd /tmp; tar cf - xv6) | gzip >xv6-rev9.tar.gz # the next one will be 9 (6/27/15) .PHONY: dist-test dist
and when I enter make qemu
there is a problem:
yuanzheng@ubuntu:~/Operating_System/xv6_sourcecode/xv6-public$ make qemu ld -m elf_i386 -N -e main -Ttext 0 -o _runproctest runproctest.o ulib.o usys.o printf.o umalloc.o ld: warning: cannot find entry symbol main; defaulting to 0000000000000000 runproctest.o: In function `runproctest': /home/yuanzheng/Operating_System/xv6_sourcecode/xv6-public/runproctest.c:26: undefined reference to `cprintf' Makefile:141: recipe for target '_runproctest' failed make: *** [_runproctest] Error 1
I don’t know why this happens..
Advertisement
Answer
in the makefile, this line:
ld -m elf_i386 -N -e main -Ttext 0 -o _runproctest runproctest.o ulib.o usys.o printf.o umalloc.o
should be:
ld -m elf_i386 -N -e main -Ttext 0 -o _runproctest runproctest.o ulib.o usys.o printf.o umalloc.o console.o
There may be other ld
commands in the make file with similar problems.
Also, per the error messages, there is no main()
function anywhere in the files used to create the _runproctest
executable. That is (usually) a strong indication that the code will not properly execute.
As an aside:
a name that begins with __
or _
followed by a capital letter are reserved for the environment.
Naming your own items with a leading underscore (probably) will work, but it is cluttering the environment name space. Strongly suggest not using any leading _
in your names