我正在尝试将游戏转换为苏联 PDP11 兼容机。由于它有严格的内存限制 - 56K RAM,我必须在运行时加载部分代码。这意味着我需要构建几个相互交叉引用符号的二进制模块。我用的是GAS和LD。
有没有办法仅使用这些工具来完成此任务?
例如,一个二进制模块文件想要加载另一个二进制模块,为此它必须知道另一个二进制文件的大小。尺寸可以作为符号使用,如下所示:
.title OtherModule
begin:
some code
end:
.equiv SizeOfTheOtherModuleInWords, ((end - begin) / 2)
Run Code Online (Sandbox Code Playgroud)
另一个例子,游戏中的每个级别单独加载,并包含从始终驻留在内存中的主引擎调用子例程的代码。
我通过链接器脚本找到了解决方案。我可以使用/DISCARD/部分从链接中排除文件。
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(pdp11)
INPUT(core.o bootstrap.o)
OUTPUT(AKU.SAV)
FileSizeCoreWords = ((FileEndCore - FileBeginCore) / 2);
SECTIONS
{
. = 0;
.text :
{
bootstrap.o (.text)
}
.data :
{
bootstrap.o (.data)
}
.bss :
{
bootstrap.o (.bss)
}
/DISCARD/ :
{
core.o
}
}
Run Code Online (Sandbox Code Playgroud) 我正在研究基本的 shell 代码和orw代码。
但是,在此过程中,我收到以下错误消息:
错误:不支持的指令
mov
这是我的 C 和汇编代码框架:
// File name: orw.c
// Compile: gcc -o orw orw.c -masm=intel
__asm__(
".global run_sh\n"
"run_sh:\n"
"push 0x67\n"
"mov rax, 0x616c662f706d742f \n"
"push rax\n"
"mov rdi, rsp\n"
"xor rsi, rsi\n"
"xor rdx, rdx\n"
"xor eax, eax\n"
"mov eax, 2\n"
"syscall"
"\n"
"mov rdi, eax\n"
"mov rsi, rsp\n"
"sub rsi, 0x30\n"
"mov rdx, 0x30\n"
"xor eax, eax\n"
"syscall"
"\n"
"mov rdi,1\n"
"mov eax,1\n"
"syscall"
);
void run_sh();
int main() { run_sh(); …Run Code Online (Sandbox Code Playgroud) 我如何跳转到 intel 汇编语法(x32 和 x64)中的已知内存地址。
我想我已经掌握了 64 位语法。例如,如果在 x64 中我想跳转到位于 的代码0x75767并且我位于0000,我会这样做:
0000: FF 25 01 00 00 00 jmp QWORD PTR [rip+0x75761]
Run Code Online (Sandbox Code Playgroud)
^ 正确吗?我想我可以使用 objdump 将这些字节分解为 x32 指令,objdump.exe -D -Mintel,i386 -b binary -m i386 test.bin结果是:
jmp DWORD PTR 0x75761
Run Code Online (Sandbox Code Playgroud)
然后只需使用clang++.exe -masm=intel -m32 -c test.o将此指令转换为 x32 字节即可,但它显示:
error: invalid operand for instruction
jmp DWORD PTR 0x75761
^
Run Code Online (Sandbox Code Playgroud)
我想避免写入任何寄存器。
我的 x64 jmp 指令正确吗?
我如何在 x32 中完成类似的事情?假设在 x32 中我需要跳转到0x400107并且我在0x400000
我正在调整 Windows 上的运行进程内存。如果我的问题有不准确的地方,请原谅我,我正在学习。
我有以下功能,涉及GAS语法中的i386程序集片段:
inline int MulDivRound(
int nNumber,
int nNumerator,
int nDenominator )
{
int nRet, nMod;
__asm__ __volatile__ (
"mov %2, %%eax \n"
"mull %3 \n"
"divl %4 \n"
"mov %%eax, %0 \n"
"mov %%edx, %1 \n"
: "=m" (nRet),
"=m" (nMod)
: "m" (nNumber),
"m" (nNumerator),
"m" (nDenominator)
: "eax", "edx"
);
return nRet + nMod*2 / nDenominator;
}
Run Code Online (Sandbox Code Playgroud)
我注意到,在一些情况下,我正在EXC_I386_DIV使用此功能崩溃.以下调用会产生这样的崩溃:
int res = MulDivRound( 4096, -566, 400 );
Run Code Online (Sandbox Code Playgroud)
我无法清楚地看到正在发生的事情导致此函数除以0:当然它只是移动4096 eax,然后乘以-566,然后将其除以400,返回除法运算结果的两个分量.任何人都可以对此有所了解吗?
我目前正在遵循启用GDT细分的指南.我正在使用GNU Assembler和Bochs进行仿真.
我知道我需要使用GDT描述符加载GDT寄存器.我已经完成了,接下来的步骤是将所有具有相对于GDT的偏移的段寄存器加载到代码/数据段描述符的各个位置.这样做的代码如下:
reloadSegments:
; Reload CS register containing code selector:
JMP 0x08:reload_CS ; 0x08 points at the new code selector
.reload_CS:
; Reload data segment registers:
MOV AX, 0x10 ; 0x10 points at the new data selector
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
RET
Run Code Online (Sandbox Code Playgroud)
但是,我无法理解如何可以隐式加载具有偏移量的CS寄存器,而不会显着跳跃到CS:IP对指向的任何内存位置 - 即,如果代码段描述符位于GDT_start + 0x10,我尝试将0x10加载到CS寄存器,虚拟机跳转到0x10:IP,我从不输入.reload_CS标签.
我的例程版本(at&t语法):
_start:
// Disable interrupts
cli
// Load GDT register with location of GDT
lgdt 0x3c
// Load location of Code …Run Code Online (Sandbox Code Playgroud) 这是我现在正在玩的代码:
# file-name: test.s
# 64-bit GNU as source code.
.global main
.section .text
main:
lea message, %rdi
push %rdi
call puts
lea message, %rdi
push %rdi
call printf
push $0
call _exit
.section .data
message: .asciz "Hello, World!"
Run Code Online (Sandbox Code Playgroud)
编译说明:gcc test.s -o test
修订版 1:
.global main
.section .text
main:
lea message, %rdi
call puts
lea message, %rdi
call printf
mov $0, %rdi
call _exit
.section .data
message: .asciz "Hello, World!"
Run Code Online (Sandbox Code Playgroud)
最终修订版(作品):
.global main
.section .text
main:
lea message, %rdi …Run Code Online (Sandbox Code Playgroud) 链接目标文件时,我得到了对“ esp”的未定义引用。
我在名为mydc.s的文件中编写了汇编代码
然后我使用创建了目标文件
as --32 -march=i386 mydc.s -o mydc.o
(这里没有错误)然后将其与
gcc -m32 -march=i386 mydc.o -o mydc
然后它创建错误消息为
(.text + 0x2a):对'esp'的未定义引用
代码如下
.section ".text"
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
input:
pushl $buffer
pushl $scanfFormat
call scanf
addl $8, %esp
## check if user input EOF
cmp $EOF, %eax
je quit
pushl $buffer
call isdigit
addl $4, esp
cmp $1, %eax
je if_digit
movl buffer, %eax
cmpl $'p', %eax
je if_p
cmpl $'q', %eax
je if_q …Run Code Online (Sandbox Code Playgroud) 我正在尝试组装一些 64 位代码,但组装失败了:
addq $0xffffff7fc0005000, %rax
Run Code Online (Sandbox Code Playgroud)
有错误:
`add' 的错误操作数类型不匹配
第一个操作数是一个 64 位值,后者是一个应该组装好的寄存器。该指令前面有一个.code64伪操作。我正在组装
x86_64-elf-as test.s -o test.o --64
Run Code Online (Sandbox Code Playgroud)
至于汇编器本身,当用--version它调用时返回:
GNU assembler (GNU Binutils) 2.32
Copyright (C) 2019 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `x86_64-elf'.
Run Code Online (Sandbox Code Playgroud) 我试图将包含宏的头文件包含到我的主程序集文件中,但编译失败。
下面是我的main.S文件
#include "common.h"
BEGIN
mov $0x0E40, %ax
int $0x10
hlt
Run Code Online (Sandbox Code Playgroud)
以下是我的common.h文件:
.macro BEGIN
LOCAL after_locals
.code16
cli
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on …Run Code Online (Sandbox Code Playgroud) C中的函数是
void f(int* out, int* in, int nbElements){
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
由于int nbElements是第一个被压入堆栈in并且out具有可变大小,我如何访问 的值nbElements?据我了解,堆栈看起来像这样:
esp
ebp
return address # -4(%ebp)
1st element of int* out # -8(%ebp)
1st element of int* in # (%ebp - 8 - 4*nbElements)
nbElements # not sure how I can access the value of this
Run Code Online (Sandbox Code Playgroud)
那么如何在nbElements不知道其地址的情况下访问的值呢?
我可以使用 GCC 将汇编代码文件转换为可重新分配的文件。
gcc -c source.S -o object.o -O2
Run Code Online (Sandbox Code Playgroud)
优化选项是否有效?我可以期望 GCC 优化我的汇编代码吗?