我正在尝试编写自己的bootloader.虽然它在QEMU,Bochs和VirtualBox中运行良好,但我似乎无法在笔记本电脑上运行.
在我的笔记本电脑上,引导加载程序与所有模拟器的行为完全不同,挂起看似随机的地方,拒绝打印,甚至跳过一些jmp $指令.
虽然我对"真实硬件"有很多麻烦,但我认为它们都有一个原因.
以下代码是一个短引导加载程序,应该打印"TEST"消息3次,然后跳转到同一位置挂起:
[BITS 16]
[ORG 0x7C00]
jmp 0x0000:start_16 ; In case bootloader is at 0x07C0:0x0000
start_16:
xor ax, ax
mov ds, ax
mov es, ax
cli ; Disable interrupts
mov ss, ax
mov sp, 0x7C00
sti ; Enable interrupts
cld ; Clear Direction Flag
; Store the drive number
mov [drive_number], dl
; Print message(s)
mov si, msg
call print_string
mov si, msg
call print_string
mov si, msg
call print_string
jmp $ ; HALT
; …Run Code Online (Sandbox Code Playgroud) 我有一个简单的调试器(使用ptrace:http://pastebin.com/D0um3bUi)来计算给定输入可执行程序执行的指令数.它使用ptrace单步执行模式来计算指令.
为此,当程序1)的可执行文件(来自gcc main.c的a.out)作为输入提供给我的测试调试器时,它会在执行指令时打印大约100k.当我使用-static选项时,它会给出10681条指令.
现在在2)我创建一个汇编程序并使用NASM进行编译和链接,然后当这个可执行文件作为测试调试器输入时,它显示8个指令作为计数,哪个是apt.
程序1)中执行的指令数量很高,因为在运行时将程序与系统库链接起来了?使用-static并将计数减少1/10.如何确保指令计数仅是程序1)中主要功能的指令,以及程序2)为调试器报告的方式?
1)
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我使用gcc来创建可执行文件.
2)
; 64-bit "Hello World!" in Linux NASM
global _start ; global entry point export for ld
section .text
_start:
; sys_write(stdout, message, length)
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, message ; message address
mov rdx, length ; message string length
syscall
; sys_exit(return_code)
mov rax, 60 ; sys_exit
mov rdi, …Run Code Online (Sandbox Code Playgroud) 这是我的计划:
void test_function(int a, int b, int c, int d){
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_function(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)
我用debug选项编译这个程序:
gcc -g my_program.c
Run Code Online (Sandbox Code Playgroud)
我使用gdb并使用intel语法反汇编test_function:
(gdb) disassemble test_function
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
我拆卸了主要的:
(gdb) …Run Code Online (Sandbox Code Playgroud) 下面是我在 Commodore 64 上进行内存复制的自我修改例程。
我写了char codes并number of repeats在一个表中,充满了screen_ram的这个套路。
我正在寻找优化建议。在这种情况下,我的优先事项是内存。
memCopy:
sourceAddress=*+1 ; mark self modifying addrres
fetchNewData:
lda data_table ; read char value into A
ldx data_table+1 ; read repeat value into x
inc sourceAddress
inc sourceAddress
cpx #00 ; if X=0
beq end ; finish copying
destination=*+1
- sta SCREEN_RAM
inc destination
dex
bne -
jmp fetchNewData
end:
rts
; data format: <char>,<number of repeats>,[<char>,<number of repeats>,...],00,00
data_table:
!by 01,03,02,02,......,00,00
Run Code Online (Sandbox Code Playgroud) 我是 64 位 x86 编码新手,但我运行的是 Ubuntu 14.04(可靠),并且我有一段非常简单的 64 位代码,我使用as进行汇编。我得到的输出具有奇怪的权限和文件类型。
当我跑步时:
as file.s
Run Code Online (Sandbox Code Playgroud)
我得到一个具有 770 权限的文件a.out。
当我执行它时,我得到这个错误:
bash: ./a.out: 无法执行二进制文件: Exec 格式错误
当我跑步时:
file ./a.out
Run Code Online (Sandbox Code Playgroud)
我得到:
./a.out:ELF 64 位 LSB 可重定位,x86-64,版本 1 (SYSV),未剥离
我使用的汇编代码是:
.section .data
.LC0:
.string "/bin/sh"
.LC1:
.string "/bin/sh"
.LC3:
.quad .LC1, 0
.text
.globl _start
_start:
.LFB0:
pushq %rbp
movq %rsp, %rbp
movq $59,%rax # System Call to execve
movq $.LC0, %rdi # Pass program to execute
movq $.LC3, %rsi # Pass command …Run Code Online (Sandbox Code Playgroud) 我是Assembly的新手,下面的代码应该通过两个不同的函数交换两个整数:首先使用swap_c然后再使用swap_asm.
但是,我怀疑,我是否需要push(我的意思是保存)汇编代码之前的每个寄存器值以及pop它们之后(就在返回之前main).换句话说,如果我在运行函数后返回不同的寄存器内容(不是像ebp或者esp只是eax,但是,只是ebx,ecx&edx),CPU会不会生我的气swap_asm?取消组装部件中的线条是否更好?
这段代码对我来说运行正常,我设法将27行汇编C代码减少到7个装配线.
ps:系统是Windows 10,VS-2013 Express.
main.c 部分
#include <stdio.h>
extern void swap_asm(int *x, int *y);
void swap_c(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
int main(int argc, char *argv[]) {
int x = 3, y = 5;
printf("before swap => x = %d y = …Run Code Online (Sandbox Code Playgroud) 当cmpw %ax -5x86-64的编码指令,来自Intel-instruction-set-reference-manual时,我有两个操作码可供选择:
3D iw CMP AX, imm16 I Valid Valid Compare imm16 with AX.
83 /7 ib CMP r/m16, imm8 MI Valid Valid Compare imm8 with r/m16.
Run Code Online (Sandbox Code Playgroud)
所以会有两个编码结果:
66 3d fb ff ; this for opcode 3d
66 83 f8 fb ; this for opcode 83
Run Code Online (Sandbox Code Playgroud)
那么哪一个更好?
我在下面尝试了一些在线反汇编程序
两者都可以反汇编到原点指令.但为什么6683fb00也有效,有效663dfb.
因此,我正在为应用程序创建管理面板,我想将所有用户问题和用户操作放入数据库,以便我可以在管理面板中显示它们。这样,管理员就不必去检查包含许多他们不需要使用的其他信息的日志文件。但我还需要自己的日志文件,以便我可以查看服务器是否发生了问题。
做到这一点的最佳方法是什么,如何在全局范围内设置这种日志记录,这样我就不必在每个控制器中手动将它们放入数据库?
我想知道ret从程序的入口点返回是否合法.
NASM示例:
section .text
global _start
_start:
ret
; Linux: nasm -f elf64 foo.asm -o foo.o && ld foo.o
; OS X: nasm -f macho64 foo.asm -o foo.o && ld foo.o -lc -macosx_version_min 10.12.0 -e _start -o foo
Run Code Online (Sandbox Code Playgroud)
ret 从堆栈中弹出一个返回地址并跳转到它.
但是堆栈的顶部字节是程序入口点的有效返回地址,还是我必须调用exit?
此外,上面的程序不会在OS X上发生段错误.它在哪里返回?
我正在尝试使用OSDev等编写操作系统。现在,我一直在制作键盘中断处理程序。当我编译操作系统并运行内核时,qemu-system-i386 -kernel kernel/myos.kernel一切运行正常。当我将所有内容放入ISO映像并尝试使用进行运行时qemu-system-i386 -cdrom myos.iso,当我按一个键时它将重新启动。我认为这是由我的中断处理程序中的某些问题或错误的IDT条目引起的。
我的键盘处理程序(AT&T语法):
.globl keyboard_handler
.align 4
keyboard_handler:
pushal
cld
call keyboard_handler_main
popal
iret
Run Code Online (Sandbox Code Playgroud)
我在C中的主要处理程序:
void keyboard_handler_main(void) {
unsigned char status;
char keycode;
/* write EOI */
write_port(0x20, 0x20);
status = read_port(KEYBOARD_STATUS_PORT);
/* Lowest bit of status will be set if buffer is not empty */
if (status & 0x01) {
keycode = read_port(KEYBOARD_DATA_PORT);
if(keycode < 0)
return;
if(keycode == ENTER_KEY_CODE) {
printf("\n");
return;
}
printf("%c", keyboard_map[(unsigned char) keycode]);
}
} …Run Code Online (Sandbox Code Playgroud) assembly ×9
x86 ×5
c ×3
x86-64 ×3
disassembly ×2
linux ×2
osdev ×2
6502 ×1
bios ×1
bootloader ×1
entry-point ×1
gcc ×1
gdb ×1
java ×1
logging ×1
macos ×1
masm ×1
nasm ×1
return ×1
spring ×1
spring-boot ×1
ubuntu-14.04 ×1