C 如何影响函数的地址?

C 如何影响函数的地址?,c,assembly,C,Assembly,是否有方法影响、设置或定义函数的(相对)地址?也许在链接器脚本中有任何可能确保函数abc()始终位于偏移量+0x0034C0处(仅举一个例子)。 我想以某种方式“控制”内存中函数的位置,使这些位置具有某种参数化。 目前,我正在寻找一种在x86上使用gcc的方法。然而,真正的应用程序应该在嵌入式设备上运行 关于您可能可以使用gcc来完成,是的。看看如何定义,然后将指令放入源代码中,以将函数放入您选择的部分 不过,由于操作系统可能已经。。。反对意见。这是更多的嵌入式使用直接 在一个完整的操作系统上控

是否有方法影响、设置或定义函数的(相对)地址?也许在链接器脚本中有任何可能确保函数abc()始终位于偏移量+0x0034C0处(仅举一个例子)。 我想以某种方式“控制”内存中函数的位置,使这些位置具有某种参数化。 目前,我正在寻找一种在x86上使用gcc的方法。然而,真正的应用程序应该在嵌入式设备上运行


关于

您可能可以使用gcc来完成,是的。看看如何定义,然后将指令放入源代码中,以将函数放入您选择的部分

不过,由于操作系统可能已经。。。反对意见。这是更多的嵌入式使用直接


在一个完整的操作系统上控制代码位置有什么意义呢?

一个典型的通用实现是一个向量表(我还听说这个称为补丁表)

首先,在C文件中编写函数:

void my_first_function(int){ /* do something */ }
void my_second_function(int){ /* do something */ }
然后,在C文件中创建一个定义表布局的结构:

struct MyVectorTable
{
  void (*first_function)(int);
  int (*second_function)(float, char);

  // all the rest
};
接下来,在C文件中创建一个静态表:

static struct MyVectorTable my_vector_table = {
  my_first_function,
  my_second_function,
};
最后将地址公开为空*

void* get_table_base_address(void) { return &my_vector_table; }
现在,您应该能够从基址获得所有函数的偏移量

如果所有函数都具有相同的调用签名,则可以通过使用函数指针数组而不是结构来简化此过程。但是,数组和结构都将保存指针,因此指针数学基本相同


这还允许您使用链接器在特定地址定位修补程序表。

IMO,最好的方法是将函数放入用户定义的部分,如上文所述。您可以找到一个简单的示例,该示例将函数
myFunc
放置在下面的4KB边界处:

通过修改链接器脚本在内存中创建新节:

/* .my_section will be the name of the section in the final executable */
.my_section : ALIGN (8)
{
    . = ALIGN (0x1000);

    KEEP(*(.mysection))    /* The section will be called ".mysection" in the
                              compiled translation unit (.obj) */

    . = ALIGN (8);
} >rom
现在,使用gcc的
属性
功能将函数放入我们刚刚创建的部分:

void myFunc(void) __attribute__ ((section(".mysection"))); // The section name to use 
                                                           // here is ".mysection", 
                                                           // not ".my_section"

// Looks like you need to use __attribute__ along with function declaration, rather 
// than with the function definition, though I'm not sure why

void myFunc(void)
{
    // ...
}
如果现在执行
objdump
,您将看到一个名为
的节。my_节
myFunc
的代码保存在地址
0x2000
,而不是
0x12e8

Disassembly of section .my_section:

000012e8 <myFunc-0xd18>:
        ...

00002000 <myFunc>:
    2000:       b508            push    {r3, lr}
    ...
节的反汇编。my_节:
000012e8:
...
00002000 :
2000:b508推送{r3,lr}
...

此代码与手臂皮质的
codesourcy gcc
suite一起使用。我不太确定x86…

IMO,如果应用程序运行在一个嵌入式设备上,我假设它有某种自定义操作系统,不要试图让它在x86上工作,然后发现它无法在该设备上运行。(好奇,为什么?)?我认为使用函数指针或类似的东西是一个很有可能的选择,但如果没有真正理解“我需要一个特殊地址上的函数”背后的真实想法,就很难知道该建议什么解决方案。@MatsPeterson:你的确是对的。我的目标是创建一个硬件软件绑定方案。更多细节可以在我对unwind答案的评论中找到。因此,这听起来更像是“我希望只有在某些身份验证成功的情况下才能访问代码块”,我可以通过以下任一方法来解决:1。将整个块放在一个部分中[例如,请参见如何在Linux中定义_init],然后如果身份验证有效,则仅将该区域映射到MMU的虚拟空间中。2.如前所述,使用函数指针,或者使用另一组指针,或者将指针设置为在身份验证失败时停止[或执行其他“这不起作用”操作]的函数。实际上,我想创建一些软硬件绑定方案。某些功能的位置应在软件开发过程中确定。在执行软件时,它从用于指导软件控制流的硬件读取身份验证信息。仅当从硬件读取正确的凭据时,后续函数调用才会指向正确的内存地址。否则,它们指向内存中错误的位置,软件停止执行/软件崩溃。@user1192748,我看到了一个类似的结果,只存储特定硬件地址(如中断向量)内容的校验和@user1192748 CRC检查的优点是,您可以简单地检查值,如果不匹配,则不运行。调用未定义的行为只会导致灾难(即,您无法控制软件何时/何地/如何“停止”,如果它“停止”)是的,使用gnu链接器,您可以控制对象的位置,通过在源文件中排列函数,您可以控制哪个函数是第一个函数和/或每个对象只有一个函数。(这并不是那么神奇)@JoshPetitt你能提供更多关于校验和方法的参考吗?