I am trying to step through the simple bootloader shown in this tutorial: http://mikeos.berlios.de/write-your-own-os.html - so I can use the Qemu monitor to inspect the general registers for educational purposes.
Eventhough I am able to connect Qemu and gdb and the breakpoint is set at the beginning of the bootloader (0x7c0), after hitting "c" on gdb the code just runs all the way till the end.
I have read kvm may "confuse" gbd with virtual memory addresses, so I disabled it. This didn't work.
I also read (Debugging bootloader with gdb in qemu) things worked when debugging Freedos boot after compiling gdb from HEAD. Instead of recompiling gdb, I tried debugging the Freedos boot - It worked!
So, I do believe my problem is actually getting the tutorial's bootloader to go through a step-by-step execution.
Other things I tried (none of them worked):
Use dozens of "si" before inserting the breakpoint
Try different breakpoint addresses
Use the -singlestep key on qemu
Here is my qemu command line:
qemu-system-i386 -fda disquete.img -boot a -s -S -monitor stdio
Here is my command sequence inside gdb:
(gdb) target remote localhost:1234
(gdb) set architecture i8086
(gdb) br *0x7c0
Then I hit "c" and it just passes the breakpoint all the way.
Versions:
$ uname -a
Linux Brod 3.8.0-30-generic #44-Ubuntu SMP Thu Aug 22 20:52:24 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ gdb --version
GNU gdb (GDB) 7.5.91.20130417-cvs-ubuntu
$ qemu --version
QEMU emulator version 1.4.0 (Debian 1.4.0+dfsg-1expubuntu4), Copyright (c) 2003-2008 Fabrice Bellard
As I am able to step through the Freedos boot, I do believe my setup is fine and I must be failing within some conceptual misunderstanding of the boot process for the bootloader tutorial I mentioned in the beginning of this post.
All help is welcome!
Because of hardware virtualization, it may be necessary to use a hardware breakpoint:
(gdb) hbreak *0x7c00
Also watch out for the correct architecture in gdb, even when using a 64-bit CPU (or kvm): The bootloader needs (gdb) set architecture i8086 as the CPU is still in real mode.
I was actually able to debug the sample bootloader I took from mikeos.berlios.de/write-your-own-os.html after rewriting it to specifically load at 0x7c00. My sources of information (other than the contributions here) were:
http://en.wikibooks.org/wiki/X86_Assembly/Bootloaders
http://viralpatel.net/taj/tutorial/hello_world_bootloader.php
The final code is this:
[BITS 16] ; Tells nasm to build 16 bits code
[ORG 0x7C00] ; The address the code will start
start:
mov ax, 0 ; Reserves 4Kbytes after the bootloader
add ax, 288 ; (4096 + 512)/ 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 0 ; Sets the data segment
mov ds, ax
mov si, texto ; Sets the text position
call imprime ; Calls the printing routine
jmp $ ; Infinite loop
texto db 'It works! :-D', 0
imprime: ; Prints the text on screen
mov ah, 0Eh ; int 10h - printing function
.repeat:
lodsb ; Grabs one char
cmp al, 0
je .done ; If char is zero, ends
int 10h ; Else prints char
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Fills the remaining boot sector with 0s
dw 0xAA55 ; Standard boot signature
Now I can step through the program and see the registers changing.
Related
I'm currently getting into bootloaders and kernel development (very much beginning)
I'm following a combination of
https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf
and the code found in
https://github.com/cfenollosa/os-tutorial
The only thing im doing differently is that I'm targeting x86_64 instead of i386. Also I'm using qemu to emulate (qemu-system-x86_64).
Now after following the GitHub repo to part 16-video-driver I get stuck as the screen driver does print some stuff to the screen but something's going on with a misalignment of data or something. So next I wanted to try to debug my program. This is also covered in part 14-checkpoint of the repo. So I built gdb for target x86_64-elf. But when I try to run qemu and gdb using system-qemu-x86_64 -s -S -fda os-image
and then just run gdb and try to connect to qemu by running target remote localhost:1234, as soon as I run that I get the following error message
Remote debugging using localhost:1234
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
Remote 'g' packet reply is too long (expected 308 bytes, got 536 bytes):
000000000000000000000000000000000000000000000000630600000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000f0ff0000000000000200000000f00000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000007f03000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000801f0000
Any ideas on what I'm missing / doing wrong? If more information is needed please let me know.
Thanks
EDIT:
I've applied the patch mentioned by #MichaelPetch and now the g packet error is gone. However it looks like gdb can't interpret my executable as after running target remote localhost:1234 and then symbol-file kernel.elf, the terminal now returns
Remote debugging using localhost:1234 warning: No executable has been
specified and target does not support determining executable automatically.
Try using the "file" command. 0x0000fb38 in ?? ()
I am however able to set breakpoints on functions and line numbers. But when trying to print variables that should be available at the current location using print terminal_buffer I get
No symbol "terminal_buffer" in current context. terminal_buffer being a variable declared in the current scope.
However when I print a variable declared outside the scope of the function in which I have put my breakpoint, an int for example, print does return a value but the value is 0 (I presume that is the initial value of the type), however it should already have been set to a new value according to my code. Also when trying next it returns Cannot find bounds of current function which leads to me thinking it's not able to interpret some part.
In my bootloader I change into protected protected mode to run the 64-bit kernel using this method:
[bits 16]
switch_to_pm:
cli ; 1. disable interrupts
lgdt [gdt_descriptor] ; 2. load the GDT descriptor
mov eax, cr0
or eax, 0x1 ; 3. set 32-bit mode bit in cr0
mov cr0, eax
jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
[bits 32]
init_pm: ; we are now using 32-bit instructions
mov ax, DATA_SEG ; 5. update the segment registers
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
mov esp, ebp
call BEGIN_PM ; 7. Call a well-known label with useful code
Any thoughts?
The reason for all the issues is that you are compiling 64-bit code and running it in 32-bit protected mode. 64-bit code will not run in that environment properly. Oddly enough it often manifests itself at first when trying to write to the video display. Often things will print but not quite the way you want. Improperly decoded instructions will cause the debugger to work erratically as you observed.
One way to fix your problem is to compile and link the kernel as a 32-bit executable. You are using a 64-bit compiler so you'll need to add -m32 CFLAGS (or your GCC command line). if using LD to link -melf_i386 will be needed. Assembling with NASM should be -felf32 rather than -felf64.
Alternatively you would have to place the processor into 64-bit long mode in the bootloader. You can read more about that process on the OSDev wiki.
If debugging 32-bit code you will probably want to use qemu-system-i386 . You will have fewer hassles.
Connect and disconnect
I got it working as detailed at: How to debug the Linux kernel with GDB and QEMU?
The key thing was connect and disconnect on GDB as:
gdb \
-ex "add-auto-load-safe-path $(pwd)" \
-ex "file vmlinux" \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote localhost:1234' \
-ex 'break start_kernel' \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set arch i386:x86-64' \
-ex 'target remote localhost:1234'
Related: Remote 'g' packet reply is too long
The book Assembly Language Step by Step provides the following code as a sandbox:
section .data
section .text
global _start
_start:
nop
//insert sandbox code here
nop
Any example that I include in the space for sandbox is creating a segmentation fault. For example, adding this code:
mov ax, 067FEh
mov bx, ax
mov cl, bh
mov ch, bl
Then compiling with:
nasm -f macho sandbox.asm
ld -o sandbox -e _start sandbox.o
creates a seg fault when I run it on my OS/X. Is there a way to get more information about what's causing the segmentation fault?
The problem you have is that you have created a program that runs past the end of the code that you have written.
When your program executes, the loader will end up issuing a jmp to your _start. Your code then runs, but you do not have anything to return to the OS at the end, so it will simply continue running, executing whatever bytes happen to be in RAM after your code.
The simplest fix would be to properly exit the code. For example:
mov eax, 0x1 ; system call number for exit
sub esp, 4 ; OS X system calls needs "extra space" on stack
int 0x80
Since you are not generating any actual output, you would need to step through with a debugger to see what's going on. After compiling you could use lldb to step through.
lldb ./sandbox
image dump sections
Make note of the address listed that is of type code for your executable (not dyld). It will likely be 0x0000000000001fe6. Continuing within lldb:
b s -a 0x0000000000001fe6
run
register read
step
register read
step
register read
At this point you should be past the NOPs and see things changing in registers. Have fun!
Does anyone know of any good tools (I'm looking for IDEs) to write assembly on the Mac. Xcode is a little cumbersome to me.
Also, on the Intel Macs, can I use generic x86 asm? Or is there a modified instruction set? Any information about post Intel.
Also: I know that on windows, asm can run in an emulated environment created by the OS to let the code think it's running on its own dedicated machine. Does OS X provide the same thing?
After installing any version of Xcode targeting Intel-based Macs, you should be able to write assembly code. Xcode is a suite of tools, only one of which is the IDE, so you don't have to use it if you don't want to. (That said, if there are specific things you find clunky, please file a bug at Apple's bug reporter - every bug goes to engineering.) Furthermore, installing Xcode will install both the Netwide Assembler (NASM) and the GNU Assembler (GAS); that will let you use whatever assembly syntax you're most comfortable with.
You'll also want to take a look at the Compiler & Debugging Guides, because those document the calling conventions used for the various architectures that Mac OS X runs on, as well as how the binary format and the loader work. The IA-32 (x86-32) calling conventions in particular may be slightly different from what you're used to.
Another thing to keep in mind is that the system call interface on Mac OS X is different from what you might be used to on DOS/Windows, Linux, or the other BSD flavors. System calls aren't considered a stable API on Mac OS X; instead, you always go through libSystem. That will ensure you're writing code that's portable from one release of the OS to the next.
Finally, keep in mind that Mac OS X runs across a pretty wide array of hardware - everything from the 32-bit Core Single through the high-end quad-core Xeon. By coding in assembly you might not be optimizing as much as you think; what's optimal on one machine may be pessimal on another. Apple regularly measures its compilers and tunes their output with the "-Os" optimization flag to be decent across its line, and there are extensive vector/matrix-processing libraries that you can use to get high performance with hand-tuned CPU-specific implementations.
Going to assembly for fun is great. Going to assembly for speed is not for the faint of heart these days.
As stated before, don't use syscall. You can use standard C library calls though, but be aware that the stack MUST be 16 byte aligned per Apple's IA32 function call ABI.
If you don't align the stack, your program will crash in __dyld_misaligned_stack_error when you make a call into any of the libraries or frameworks.
The following snippet assembles and runs on my system:
; File: hello.asm
; Build: nasm -f macho hello.asm && gcc -o hello hello.o
SECTION .rodata
hello.msg db 'Hello, World!',0x0a,0x00
SECTION .text
extern _printf ; could also use _puts...
GLOBAL _main
; aligns esp to 16 bytes in preparation for calling a C library function
; arg is number of bytes to pad for function arguments, this should be a multiple of 16
; unless you are using push/pop to load args
%macro clib_prolog 1
mov ebx, esp ; remember current esp
and esp, 0xFFFFFFF0 ; align to next 16 byte boundary (could be zero offset!)
sub esp, 12 ; skip ahead 12 so we can store original esp
push ebx ; store esp (16 bytes aligned again)
sub esp, %1 ; pad for arguments (make conditional?)
%endmacro
; arg must match most recent call to clib_prolog
%macro clib_epilog 1
add esp, %1 ; remove arg padding
pop ebx ; get original esp
mov esp, ebx ; restore
%endmacro
_main:
; set up stack frame
push ebp
mov ebp, esp
push ebx
clib_prolog 16
mov dword [esp], hello.msg
call _printf
; can make more clib calls here...
clib_epilog 16
; tear down stack frame
pop ebx
mov esp, ebp
pop ebp
mov eax, 0 ; set return code
ret
Recently I wanted to learn how to compile Intel x86 on Mac OS X:
For nasm:
-o hello.tmp - outfile
-f macho - specify format
Linux - elf or elf64
Mac OSX - macho
For ld:
-arch i386 - specify architecture (32 bit assembly)
-macosx_version_min 10.6 (Mac OSX - complains about default specification)
-no_pie (Mac OSX - removes ld warning)
-e main - specify main symbol name (Mac OSX - default is start)
-o hello.o - outfile
For Shell:
./hello.o - execution
One-liner:
nasm -o hello.tmp -f macho hello.s && ld -arch i386 -macosx_version_min 10.6 -no_pie -e _main -o hello.o hello.tmp && ./hello.o
Let me know if this helps!
I wrote how to do it on my blog here:
http://blog.burrowsapps.com/2013/07/how-to-compile-helloworld-in-intel-x86.html
For a more verbose explanation, I explained on my Github here:
https://github.com/jaredsburrows/Assembly
Running assembly Code on Mac is just 3 steps away from you. It could be done using XCODE but better is to use NASM Command Line Tool.
For My Ease I have already installed Xcode, if you have Xcode installed its good.
But You can do it without XCode as well.
Just Follow:
First Install NASM using Homebrew brew install nasm
convert .asm file into Obj File using this command nasm -f macho64 myFile.asm
Run Obj File to see OutPut using command ld -macosx_version_min 10.7.0 -lSystem -o OutPutFile myFile.o && ./64
Simple Text File named myFile.asm is written below for your convenience.
global start
section .text
start:
mov rax, 0x2000004 ; write
mov rdi, 1 ; stdout
mov rsi, msg
mov rdx, msg.len
syscall
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .data
msg: db "Assalam O Alaikum Dear", 10
.len: equ $ - msg
Also, on the Intel Macs, can I use generic x86 asm? or is there a modified instruction set? Any information about post Intel Mac assembly helps.
It's the same instruction set; it's the same chips.
The features available to use are dependent on your processor. Apple uses the same Intel stuff as everybody else. So yes, generic x86 should be fine (assuming you're not on a PPC :D).
As far as tools go, I think your best bet is a good text editor that 'understands' assembly.
Forget about finding a IDE to write/run/compile assembler on Mac. But, remember mac is UNIX. See http://asm.sourceforge.net/articles/linasm.html. A decent guide (though short) to running assembler via GCC on Linux. You can mimic this. Macs use Intel chips so you want to look at Intel syntax.
So i was wondering if there is any? I know afd on windows but not sure anything about mac?
And this his how i am using nasam on the following code: nasm a.asm -o a.com -l a.lst
[org 0x100]
mov ax, 5
mov bx, 10
add ax, bx
mov bx, 15
add ax, bx
mov ax, 0x4c00
int 0x21
On windows i know a debugger name afd which help me to step through each statement but not sure how i can do this using gdb.
And neither i am able to execute this .com file, am i supposed to make some other file here?
Why are you writing 16-bit code that makes DOS syscalls? If you want to know how to write asm that's applicable to your OS, take a look the code generated by "gcc -S" on some C code... (Note that code generated this way will have operands reversed, and is meant to be assembled with as instead of nasm)
Further, are you aware what this code is doing? It reads to me like this:
ax = 5
bx = 10
ax += bx
bx = 15
ax += bx
ax = 0x4c00
int 21h
Seems like this code is equivalent to:
mov bx, 15
mov ax, 4c00
int 21h
Which according to what I see here, is exit(0). You didn't need to change bx either...
But. This doesn't even apply to what you were trying to do, because Mac OS X is not MS-DOS, does not know about DOS APIs, cannot run .COM files, etc. I wasn't even aware that it can run 16 bit code. You will want to look at nasm's -f elf option, and you will want to use registers like eax rather than ax.
I've not done assembly programming on OS X, but you could theoretically do something like this:
extern exit
global main
main:
push dword 0
call exit
; This will never get called, but hey...
add esp, 4
xor eax, eax
ret
Then:
nasm -f elf foo.asm -o foo.o
ld -o foo foo.o -lc
Of course this is relying on the C library, which you might not want to do. I've omitted the "full" version because I don't know what the syscall interface looks like on Mac. On many platforms your entry point is the symbol _start and you do syscalls with int 80h or sysenter.
As for debugging... I would also suggest GDB. You can advance by a single instruction with stepi, and the info registers command will dump register state. The disassemble command is also helpful.
Update: Just remembered, I don't think Mac OS X uses ELF... Well.. Much of what I wrote still applies. :-)
Xcode ships with GDB, the GNU Debugger.
Xcode 4 and newer ships with LLDB instead.
As others have said, use GDB, the gnu debugger. In debugging assembly source, I usually find it useful to load a command file that contains something like the following:
display/5i $pc
display/x $eax
display/x $ebx
...
display/5i will display 5 instructions starting with the next to be executed. You can use the stepi command to step execution one instruction at a time. display/x $eax displays the contents of the eax register in hex. You will also likely want to use the x command to examine the contents of memory: x/x $eax, for example, prints the contents of the memory whose address is stored in eax.
These are a few of many commands. Download the GDB manual and skim through it to find other commands you may be interested in using.
IDA Pro does work on the Mac after a fashion (UI still runs on Windows; see an example).
Does anyone know of any good tools (I'm looking for IDEs) to write assembly on the Mac. Xcode is a little cumbersome to me.
Also, on the Intel Macs, can I use generic x86 asm? Or is there a modified instruction set? Any information about post Intel.
Also: I know that on windows, asm can run in an emulated environment created by the OS to let the code think it's running on its own dedicated machine. Does OS X provide the same thing?
After installing any version of Xcode targeting Intel-based Macs, you should be able to write assembly code. Xcode is a suite of tools, only one of which is the IDE, so you don't have to use it if you don't want to. (That said, if there are specific things you find clunky, please file a bug at Apple's bug reporter - every bug goes to engineering.) Furthermore, installing Xcode will install both the Netwide Assembler (NASM) and the GNU Assembler (GAS); that will let you use whatever assembly syntax you're most comfortable with.
You'll also want to take a look at the Compiler & Debugging Guides, because those document the calling conventions used for the various architectures that Mac OS X runs on, as well as how the binary format and the loader work. The IA-32 (x86-32) calling conventions in particular may be slightly different from what you're used to.
Another thing to keep in mind is that the system call interface on Mac OS X is different from what you might be used to on DOS/Windows, Linux, or the other BSD flavors. System calls aren't considered a stable API on Mac OS X; instead, you always go through libSystem. That will ensure you're writing code that's portable from one release of the OS to the next.
Finally, keep in mind that Mac OS X runs across a pretty wide array of hardware - everything from the 32-bit Core Single through the high-end quad-core Xeon. By coding in assembly you might not be optimizing as much as you think; what's optimal on one machine may be pessimal on another. Apple regularly measures its compilers and tunes their output with the "-Os" optimization flag to be decent across its line, and there are extensive vector/matrix-processing libraries that you can use to get high performance with hand-tuned CPU-specific implementations.
Going to assembly for fun is great. Going to assembly for speed is not for the faint of heart these days.
As stated before, don't use syscall. You can use standard C library calls though, but be aware that the stack MUST be 16 byte aligned per Apple's IA32 function call ABI.
If you don't align the stack, your program will crash in __dyld_misaligned_stack_error when you make a call into any of the libraries or frameworks.
The following snippet assembles and runs on my system:
; File: hello.asm
; Build: nasm -f macho hello.asm && gcc -o hello hello.o
SECTION .rodata
hello.msg db 'Hello, World!',0x0a,0x00
SECTION .text
extern _printf ; could also use _puts...
GLOBAL _main
; aligns esp to 16 bytes in preparation for calling a C library function
; arg is number of bytes to pad for function arguments, this should be a multiple of 16
; unless you are using push/pop to load args
%macro clib_prolog 1
mov ebx, esp ; remember current esp
and esp, 0xFFFFFFF0 ; align to next 16 byte boundary (could be zero offset!)
sub esp, 12 ; skip ahead 12 so we can store original esp
push ebx ; store esp (16 bytes aligned again)
sub esp, %1 ; pad for arguments (make conditional?)
%endmacro
; arg must match most recent call to clib_prolog
%macro clib_epilog 1
add esp, %1 ; remove arg padding
pop ebx ; get original esp
mov esp, ebx ; restore
%endmacro
_main:
; set up stack frame
push ebp
mov ebp, esp
push ebx
clib_prolog 16
mov dword [esp], hello.msg
call _printf
; can make more clib calls here...
clib_epilog 16
; tear down stack frame
pop ebx
mov esp, ebp
pop ebp
mov eax, 0 ; set return code
ret
Recently I wanted to learn how to compile Intel x86 on Mac OS X:
For nasm:
-o hello.tmp - outfile
-f macho - specify format
Linux - elf or elf64
Mac OSX - macho
For ld:
-arch i386 - specify architecture (32 bit assembly)
-macosx_version_min 10.6 (Mac OSX - complains about default specification)
-no_pie (Mac OSX - removes ld warning)
-e main - specify main symbol name (Mac OSX - default is start)
-o hello.o - outfile
For Shell:
./hello.o - execution
One-liner:
nasm -o hello.tmp -f macho hello.s && ld -arch i386 -macosx_version_min 10.6 -no_pie -e _main -o hello.o hello.tmp && ./hello.o
Let me know if this helps!
I wrote how to do it on my blog here:
http://blog.burrowsapps.com/2013/07/how-to-compile-helloworld-in-intel-x86.html
For a more verbose explanation, I explained on my Github here:
https://github.com/jaredsburrows/Assembly
Running assembly Code on Mac is just 3 steps away from you. It could be done using XCODE but better is to use NASM Command Line Tool.
For My Ease I have already installed Xcode, if you have Xcode installed its good.
But You can do it without XCode as well.
Just Follow:
First Install NASM using Homebrew brew install nasm
convert .asm file into Obj File using this command nasm -f macho64 myFile.asm
Run Obj File to see OutPut using command ld -macosx_version_min 10.7.0 -lSystem -o OutPutFile myFile.o && ./64
Simple Text File named myFile.asm is written below for your convenience.
global start
section .text
start:
mov rax, 0x2000004 ; write
mov rdi, 1 ; stdout
mov rsi, msg
mov rdx, msg.len
syscall
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .data
msg: db "Assalam O Alaikum Dear", 10
.len: equ $ - msg
Also, on the Intel Macs, can I use generic x86 asm? or is there a modified instruction set? Any information about post Intel Mac assembly helps.
It's the same instruction set; it's the same chips.
The features available to use are dependent on your processor. Apple uses the same Intel stuff as everybody else. So yes, generic x86 should be fine (assuming you're not on a PPC :D).
As far as tools go, I think your best bet is a good text editor that 'understands' assembly.
Forget about finding a IDE to write/run/compile assembler on Mac. But, remember mac is UNIX. See http://asm.sourceforge.net/articles/linasm.html. A decent guide (though short) to running assembler via GCC on Linux. You can mimic this. Macs use Intel chips so you want to look at Intel syntax.