使用指针作为函数参数时的段前缀 [英] Segment prefix when using pointers as function parameters

查看:114
本文介绍了使用指针作为函数参数时的段前缀的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个汇编程序/c问题.我只是阅读了有关段前缀的信息,例如ds:varX等.前缀对于逻辑地址的计算很重要.我也读过,该默认值是"ds",一旦您使用ebp寄存器来计算地址,就会立即使用"ss".对于代码"cs"是默认值.一切都说得通. 现在我在c中有以下内容:

int x; // some static var in ds

void test(int *p){
...
*p =5;

}

... main(){

test(&x);
//now x is 5
}

如果您现在考虑测试功能的实现...,您将获得指向x的指针.如果要取消引用指针,则首先要从堆栈中获取指针值(x的地址)并将其保存在eax中.然后,您可以取消引用eax以更改x的值.但是C编译器如何知道给定的指针(地址)是否引用了堆栈上的内存(例如,如果我从另一个函数调用test并将一个localvariable的地址作为参数进行测试)或数据段?完整的逻辑地址如何计算?该函数无法知道给定地址偏移量与哪个段有关..?!

解决方案

在一般情况下,在分段平台上,您不能按照您的建议将指针值读入eax".在分段平台上,指针通常将同时保留段值和偏移值,这意味着读取这样的指针将意味着至少初始化两个 寄存器(段和偏移),而不仅仅是初始化一个eax./p>

但是在特定情况下,它取决于所谓的内存模型.分段平台上的编译器支持几种内存模型.

对于初学者来说,出于显而易见的原因,只要段寄存器保持正确的值,使用哪个段寄存器都没有关系.例如,如果DSES寄存器内部保存相同的值,则DS:<offset>将指向与ES:<offset>相同的内存位置.

在所谓的微型"内存模型中,例如,所有段寄存器都具有相同的值,即所有内容(代码,数据,堆栈)都可以放入一个段中(这就是为什么它被称为微小").在这种内存模型中,每个指针只是该段中的偏移量,当然,与该偏移量一起使用哪个段寄存器都没有关系.

在更大"的内存模型中,您可以将代码(CS),堆栈(SS)和数据(DS)的段分开.但是在这种内存模型上,指针对象通常会在其中保留地址的 both 和偏移量部分.在您的示例中,指针p实际上是一个两部分的对象,同时保留了段值和偏移值.为了取消引用此类指针,编译器将生成代码,该代码将从p读取段和偏移量值,并同时使用它们.例如,段值将被读入ES寄存器,而偏移值将被读入si寄存器.然后,该代码将访问ES:[di]以便读取*p值.

还有中间"内存模型,当代码存储在一个段(CS)中,而数据和堆栈都存储在另一段中时,因此DSSS将具有相同的值.显然,在该平台上,无需区分DSSS.

在最大的内存模型中,您可以有多个数据段.在这种情况下,很明显,以分段模式进行正确的数据寻址实际上并不是选择适当的段寄存器的问题(就像您似乎相信的那样),而是要占用几乎所有 any 段的问题注册,然后使用正确的值对其进行初始化.

I have an assembler/c question. I just read about segment prefixes, for example ds:varX and so on. The prefix is important for the calculation of the logical address. I read too, that default is "ds" and as soon as you use the ebp register to calculate an address, "ss" is used. For code "cs" is default. That all makes sense. Now I have the following in c:

int x; // some static var in ds

void test(int *p){
...
*p =5;

}

... main(){

test(&x);
//now x is 5
}

If you now think about the implemention of test-function... you get the pointer to x on the stack. If you want to dereference the pointer, you first get the pointer-value(address of x) from the stack and save it in eax for example. Then you can dereference eax to change the value of x. But how does the c-compiler know if the given pointer(address) references memory on the stack (for example if i call test from another function and push the address of a localvariable as parameter for test) or the data segment? How is the full logical address calculated? The function cannot know which segment the given address offset relates to..?!

解决方案

In general case, on a segmented platform your can't just read the pointer value "into eax" as you suggest. On a segmented platform the pointer would generally hold both the segment value and offset value, meaning that reading such a pointer would imply initializing at least two registers - segment and offset - not just one eax.

But in specific cases it depends on so called the memory model. Compilers on segmented platforms supported several memory models.

For starters, for obvious reasons it does not matter which segment register you use as long as the segment register holds the correct value. For example, if DS and ES registers hold the same value inside, then DS:<offset> will point to the same location in memory as ES:<offset>.

In so called "tiny" memory model, for one example, all segment registers were holding the same value, i.e. everything - code, data, stack - would fit in one segment (which is why it was called "tiny"). In this memory model each pointer was just an offset in this segment and, of course, it simply didn't matter which segment register to use with that offset.

In "larger" memory models you could have separate segments for code (CS), stack (SS) and data (DS). But on such memory models pointer object would normally hold both the offset and segment part of the address inside of it. In your example pointer p would actually be a two-part object, holding both segment value and offset value at the same time. In order to dereference such pointer the compiler would generate the code that would read both segment and offset values from p and use both of them. For example, the segment value would be read into ES register, while the offset value would be read into si register. The code would then access ES:[di] in order to read *p value.

There were also "intermediate" memory models, when code would be stored in one segment (CS), while data and stack would both be stored in another segment, so DS and SS would hold the same value. On that platform, obviously, there was no need to differentiate between DS and SS.

In the largest memory models you could have multiple data segments. In this case it is rather obvious that proper data addressing in segmented mode is not really a matter of choosing the proper segment register (as you seem to believe), but rather a matter of taking pretty much any segment register and initializing it with the correct value before performing the access.

这篇关于使用指针作为函数参数时的段前缀的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆