汇编程序如何将常量作为数据放在文件中,以及如何以这种方式执行?

时间:2013-07-26 21:16:03

标签: assembly

例如,在Assembly x86中,我们可以使用.data条目部分并静态定义这样的数据字节:

MSG db 'CAGA', AAFF

我的问题是关于汇编程序如何或者用什么来实现插入二进制文件的数据,假设我们正在组装成平面二进制(bin)文件。

我想知道,因为我正在尝试反编译,并且更好地了解如何使用机器代码编程。

请参阅,我想在机器代码中编写系统软件代码,但Assembler抽象出一些机器代码概念(如静态数据声明,对齐,指令宽度,语句结构,操作数或代码),我在停滞不前。

我只是问一下,就机器代码而言,它是如何在这些基本原则中制定的:

如何将程序的.data部分静态添加到文件中,以及在CPU获取指令时如何在运行时/处理时使用它?例如,在下面的程序中,这是FASM上的Intel语法汇编代码中的x86引导加载程序,

    [BITS 16]   ;Tells the assembler that its a 16 bit code
[ORG 0x7C00]    ;Origin, tell the assembler that where the code will
                ;be in memory after it is been loaded

MOV SI, HelloString ;Store string pointer to SI
CALL PrintString    ;Call print string procedure
JMP $       ;Infinite loop, hang it here.


PrintCharacter: ;Procedure to print character on screen
    ;Assume that ASCII value is in register AL
MOV AH, 0x0E    ;Tell BIOS that we need to print one charater on screen.
MOV BH, 0x00    ;Page no.
MOV BL, 0x07    ;Text attribute 0x07 is lightgrey font on black background

INT 0x10    ;Call video interrupt
RET     ;Return to calling procedure



PrintString:    ;Procedure to print string on screen
    ;Assume that string starting pointer is in register SI

next_character: ;Lable to fetch next character from string
MOV AL, [SI]    ;Get a byte from string and store in AL register
INC SI      ;Increment SI pointer
OR AL, AL   ;Check if value in AL is zero (end of string)
JZ exit_function ;If end then return
CALL PrintCharacter ;Else print the character which is in AL register
JMP next_character  ;Fetch next character from string
exit_function:  ;End label
RET     ;Return from procedure


;Data
HelloString db 'Hello World', 0 ;HelloWorld string ending with 0

TIMES 510 - ($ - $$) db 0   ;Fill the rest of sector with 0
DW 0xAA55           ;Add boot signature at the end of bootloader

HelloString db'Hello World',0 ”静态插入到bin文件中为0和1,但是如何在机器代码中将静态二进制数据作为操作数添加通过将字符串指针地址存储到寄存器来到MOV SI指令?

基本上,如何将作为代码操作数执行的文件中的静态二进制数据字节移入源索引寄存器?

2 个答案:

答案 0 :(得分:0)

MOV SI, HelloString

的简写

MOV SI, OFFSET HelloString

实际的字符串HelloString放在二进制流中,就像代码作为字节序列一样。对于分段代码,它通常位于一个单独的数据段中,可以根据平台改变名称。对于像COM文件这样的东西,数据通常只跟随代码区域,通常从适当对齐的地址开始。

更新:

我现在无法访问16位系统,但这里的内容类似于32位x86代码:

Binary code    Instruction
BEA43F4600     mov esi, offset @HelloString  
E8F2FFFFFF     call PrintString
EBFE           @1: jmp @1
48656C6C6F     @HelloString: "Hello"

当然@HelloString的实际偏移量和PrintString的实际地址取决于上下文。

答案 1 :(得分:0)

您的问题的答案取决于您的二进制文件的执行方式。

假设目前使用的操作系统如Linux或MS-windows, 二进制文件很复杂,有标题信息等。让我们忽略那个和 集中程序在记忆中的样子。

稍微简单一些。

代码区

代码序言

MOV AL,BL   ...

代码后缀

数据区

MYDATA:    数据“caga”,0AH

该地区传统上称为分段。现在这个名字被英特尔劫持,它们被微软和Linux(ELF)称为部分。但是有一种强烈的关系。 MOV是程序启动的地方,但需要设置前置  并为一个后置(或你永远不会再回到Linux)。 在奔腾的典型Linux / Windows情况下,您会看到英特尔段硬件支持这些部分。底线是,您将无法跳转到MYDATA,即将程序计数器设置为包含MYDATA。相反,硬件将在Linux上对您进行“分段故障”处理,并且可能是Windows上的蓝屏。

可以肯定的是,您可以执行“数据”,因为实际上代码只是位于正确位置和时间的数据。例如。你可以通过输入一行来强制执行以下内容 SECTION .text

(傻,我知道。我不是这样做的。)

在汇编程序代码部分中,您可以说 MOV AL,BL 它将在两个连续的字节中将0x88和0xD8放在代码段中。 如果你把

,可以有同样的效果

DB 0x88, 0xD8

在您的计划中的完全相同的位置。

您将理解上述内容已大大简化。例如。典型的ELF二进制文件可以轻松包含20个部分。它对于英特尔来说也有些具体,但具体比抽象更容易理解。

你的例子显然是一个启动的情况。它不完整,因为缺少HelloString。现在,如果我们将它添加到程序的末尾,则将HelloString记为地址,即数字。在组装MOV SI,..指令时,留下一个孔来填充该数字。在处理完整个文件一次之后,HelloString地址已知并且汇编程序将其填入。

Groetjes Albert