我已经学习了编译器和汇编语言,所以我想编写自己的汇编程序作为练习。但我有一些问题;
如何计算@DATA 或 OFFSET/ADDR VarA 等段的地址?
以一个简单的汇编程序为例:
.model small
.stack 1024
.data
msg db 128 dup('A')
.code
start:
mov ax,@data
mov ax,ds
mov dx, offset msg
; DS:DX points at msg
mov ah,4ch
int 21h ; exit program without using msg
end
Run Code Online (Sandbox Code Playgroud)
那么汇编器是如何计算段的段地址的@data呢?
它如何知道将什么放入立即数mov dx, offset msg?
compiler-construction assembly masm memory-segmentation x86-16
我正在尝试使用gdb在KMines中查找当前的标志计数.我知道我应该首先寻找内存映射以避免不存在的内存位置.所以我运行info proc mappings命令来查看内存段.我0xd27000-0x168b000从结果中获取了一个随机内存gap()并执行了如下命令:find 0x00d27000, 0x0168b000, 10
但我得到了warning: Unable to access 1458 bytes of target memory at 0x168aa4f, halting search.错误.虽然地址0x168aa4f介于0xd27000和0x168b000之间,但gdb表示它无法访问它.为什么会这样?我该怎么做才能避免这种情况?或者有没有办法忽略未映射/不可访问的内存位置?
编辑:我试图将地址0x168aa4f的值设置为1并且它可以工作,因此gdb实际上可以访问该地址,但在与find命令一起使用时会出错.但为什么?
我阅读了许多文章和 S/O 答案说(在 linux x86_64 上)FS(或某些变体中的 GS)引用了一个特定于线程的页表条目,然后它给出了一个指向可共享的实际数据的指针数组数据。当线程被交换时,所有的寄存器都被切换,因此线程基页会发生变化。线程变量通过名称访问,只需要 1 个额外的指针跃点,并且引用的值可以共享给其他线程。一切都好,说得通。
事实上,如果你查看__errno_location(void)背后的函数的代码errno,你会发现类似的东西(这是来自 musl,但 gnu 并没有太大的不同):
static inline struct pthread *__pthread_self()
{
struct pthread *self;
__asm__ __volatile__ ("mov %%fs:0,%0" : "=r" (self) );
return self;
}
Run Code Online (Sandbox Code Playgroud)
来自 glibc:
=> 0x7ffff6efb4c0 <__errno_location>: endbr64
0x7ffff6efb4c4 <__errno_location+4>: mov 0x6add(%rip),%rax # 0x7ffff6f01fa8
0x7ffff6efb4cb <__errno_location+11>: add %fs:0x0,%rax
0x7ffff6efb4d4 <__errno_location+20>: retq
Run Code Online (Sandbox Code Playgroud)
所以我的期望是 FS 的实际值会因每个线程而改变。例如,在调试器下, gdb: info regor p $fs,我会看到 FS 的值在不同的线程中是不同的,但没有: ds, es, fs, gs 一直都为零。
在我自己的代码中,我写了类似下面的内容并得到相同的结果 - FS 没有改变,但 TLV “有效”:
struct …Run Code Online (Sandbox Code Playgroud) 在使用GDB调试程序时,有什么方法可以读取特定于x86-64模型的寄存器,尤其是IA32_FS_BASE和IA32_GS_BASE?
使用像Intel的Pintool这样的动态工具包的解决方案是不太可取的,但是同样可以理解。
在 x86 中,当您想要访问内存地址时,您将指定一个地址,该地址将通过两个阶段转换为内存地址:分段和分页:
但是在 x64 中也使用分段吗?(我认为它没有被使用,但我不确定它是不是在所有情况下都使用,或者在某些情况下使用它)。
我正在从反汇编中调试一些代码(没有可用的源代码),并且有许多指令通过ds段寄存器访问数据,例如这样的:
66 3B 05 8A B1 43 00 cmp ax,word ptr ds:[43B18Ah]
Run Code Online (Sandbox Code Playgroud)
你如何让 Visual Studio 调试器告诉你ds段寄存器的偏移量,以便我可以检查它所指的内存?Watch 窗口似乎不接受像ds:[0x43B18A]或变体这样的表达式;它会告诉我那ds是 0,但这并没有告诉我段 0 的偏移量是多少。
是否有一些特殊的语法,或者这是 VS 无法做到的?使用其他调试器(例如 WinDbg 或 ntsd)会更好吗?
我正在学习英特尔手册中的计算机体系结构。我的理解是,我们给出的指令是由段选择器和偏移量组成的逻辑地址。它基本上是CS register<<4 + offset。在Segment Selector映射到GDT或LDT为在给定TI的段选择的位。GDT 由Segment Descriptorshave BASE, LIMITand组成,RPL输出是基地址。这个base address+offset提供了logical address.
什么是决定段寄存器(其中的规则SS,DS等),适用于不同的存储操作?例如,什么决定了哪个段用于mov eax, [edi]?
我知道操作系统通过使用分段和特权级别来限制对内核代码和数据的访问。然而,用户可以更改段寄存器的值,如果以下代码执行成功,我们似乎可以访问内核数据:
mov eax, 0x10
mov es, ax #point selector to the item 2 in GDT with RPL 0, which is the data segment
les bx, [0]
Run Code Online (Sandbox Code Playgroud)
所以我想知道阻止此代码成功执行的机制是什么?
操作系统中的分段是一个与时间本身一样古老的概念。至少根据我的教授的说法,大多数现代操作系统已经放弃了分段的概念,现在主要依靠分页来实现内存保护,从而防止每个进程访问除自己的内存之外的任何其他内存。那么我们如何在 C 中仍然遇到“分段错误”。在现代操作系统中,我们是否仍然将分段作为一个抽象概念?
c operating-system x86-64 segmentation-fault memory-segmentation
测试.S
.text
.global _start
_start:
xor %ax, %ax
mov %ax, %ds
mov %ax, %ss
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
Run Code Online (Sandbox Code Playgroud)
我通过这样做得到了反汇编代码文件
$ x86_64-elf-gcc -g -c -O0 -m32 -fno-pie -fno-stack-protector -fno-asynchronous-unwind-tables .\test.S
$ x86_64-elf-ld .\test.o -m elf_i386 -Ttext=0x7c00 -o test.elf
$ x86_64-elf-objdump -x -d -S -m i386 ./test.elf > test_dis.txt
Run Code Online (Sandbox Code Playgroud)
测试_dis.txt
./test.elf: file format elf32-i386
./test.elf
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00007c00
Program Header:
LOAD off 0x00000000 vaddr 0x00007000 paddr 0x00007000 align 2**12
filesz …Run Code Online (Sandbox Code Playgroud)