函数如何存储在内存中?

Nei*_*eil 9 c linux memory function objdump

我一直在深入研究Linux和C,我很好奇函数是如何存储在内存中的.我有以下功能:

void test(){
    printf( "test\n" );
}
Run Code Online (Sandbox Code Playgroud)

很简单.当我在具有此功能的可执行文件上运行objdump时,我得到以下内容:

08048464 <test>:
 8048464:       55                      push   %ebp
 8048465:       89 e5                   mov    %esp,%ebp
 8048467:       83 ec 18                sub    $0x18,%esp
 804846a:       b8 20 86 04 08          mov    $0x8048620,%eax
 804846f:       89 04 24                mov    %eax,(%esp)
 8048472:       e8 11 ff ff ff          call   8048388 <printf@plt>
 8048477:       c9                      leave
 8048478:       c3                      ret
Run Code Online (Sandbox Code Playgroud)

一切看起来都正确.有趣的是,当我运行以下代码时:

int main( void ) {
    char data[20];
    int i;    
    memset( data, 0, sizeof( data ) );
    memcpy( data, test, 20 * sizeof( char ) );
    for( i = 0; i < 20; ++i ) {
        printf( "%x\n", data[i] );
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到以下(这是不正确的):

55
ffffff89
ffffffe5
ffffff83
ffffffec
18
ffffffc7
4
24
10
ffffff86
4
8
ffffffe8
22
ffffffff
ffffffff
ffffffff
ffffffc9
ffffffc3
Run Code Online (Sandbox Code Playgroud)

如果我选择省略memset(数据,0,sizeof(数据)); 行,然后最右边的字节是正确的,但其中一些仍然有前导1.

有没有人对原因有任何解释

A)使用memset清除我的数组会导致函数的错误(编辑:不准确)表示,以及

解决方案:是由于使用了memset(数据,0,sizeof(数据)),而不是memset(数据,0,20*sizeof(unsigned char)).内存未完全设置,因为它只查看指针大小而不是整个数组的大小.

B)这个字节存储在内存中是什么?整型?炭?我不太明白这里发生了什么.(澄清:我将使用什么类型的指针来遍历内存中的这些数据?)

解决方案:我很蠢.我忘记了unsigned关键字,这就是整个问题的来源:(

任何帮助将不胜感激 - 我在寻找这个时找不到任何东西.

尼尔

PS:我的直接想法是,这是x86具有不以字节或半字节边界结束的指令的结果.但这并没有多大意义,也不应该造成任何问题.

感谢Will用char类型指出我的错误.它应该是unsigned char.我仍然对如何访问单个字节感到好奇.

Wil*_*ill 6

我相信你chars符号扩展到整数的宽度.您可以通过在打印时显式地转换值来获得更接近您想要的结果.

  • 这些值的高位为零.扩展零位有点不可见.问题很严重. (4认同)

Mat*_*son 4

这是您尝试执行的代码的一个更简单的情况:

int main( void ) {
    unsigned char *data = (unsigned char *)test;
    int i;    
    for( i = 0; i < 20; ++i ) {
        printf( "%02x\n", data[i] );
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我所做的更改是删除多余的缓冲区,而不是使用指向 的指针test,使用unsigned char代替char,并将 更改printf为 use %02x,以便它始终打印两个字符(它不会修复出现的“负”数ffffff89) - 这是通过unsigned数据指针修复的)。

x86 中的所有指令都以字节边界结束,编译器通常会插入额外的“填充指令”以确保分支目标与 4、8 或 16 字节边界对齐以提高效率。