使用自定义入口点运行程序时(使用gcc 7.4.0),scanf会产生segfault

Luk*_*rst 11 c gcc

考虑以下代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("main\n");
    int a;
    scanf("%d", &a);
    printf("a = %d\n", a);
    return 0;
}

int main1() {
    printf("main1\n");
    int a;
    scanf("%d", &a);
    printf("a = %d\n", a);
    exit(0);
    return 0;
}

int main2() {
    printf("main2\n");
    int a = getchar() - '0';
    int b = getchar() - '0';
    int c = getchar() - '0';
    printf("a = %d\n", 100 * a + 10 * b + c);
    exit(0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

假设代码位于一个名为test.c的文件中,则以下代码可以正常工作(它显示“ a = 123”):

gcc -o test test.c
echo 123 | ./test
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用自定义入口点运行该程序,则会出现可怕的Segmentation错误:

gcc -o test test.c -e"main1"
echo 123 | ./test
Run Code Online (Sandbox Code Playgroud)

但是,如果我用三个getchar替换了scanf,尽管使用了一个自定义的入口点,该程序仍然可以正常运行:

gcc -o test test.c -e"main2"
echo 123 | ./test
Run Code Online (Sandbox Code Playgroud)

为了使事情更加有趣,这些问题在gcc 7.4.0中发生,而在gcc 4.8.4中则没有。

有任何想法吗?

Kon*_*lph 12

-e命令行标志重新定义了实际程序的入口点,而不是“用户”入口点。默认情况下,将GCC与GNU C标准库(glibc)一起使用时,此入口点称为_start,它将在调用用户提供的main功能之前执行进一步的设置。

如果要替换此入口点并继续使用glibc,则需要自己执行进一步的设置。但是,您也可以使用以下方法替换main入口点,该方法要简单得多:

gcc -c test.c
objcopy --redefine-sym main1=main test.o
gcc -o test test.o
Run Code Online (Sandbox Code Playgroud)

请注意,这仅在您main在代码中定义的情况下才有效,否则将从链接器中收到“'main'的多个定义”错误。