相关疑难解决方法(0)

在C中_start()有什么用?

我从同事那里了解到,无需编写函数即可编写和执行C程序main().它可以在下面完成

withoutMain.c

/* Compile this with gcc -nostartfiles */

#include <stdlib.h>

void _start() {
  int ret = my_main();
  exit(ret); 
}

int my_main() {
  puts("This is a program without a main() function!");
  return 0; 
}
Run Code Online (Sandbox Code Playgroud)

将其编译为: my_main.c

运行方式为: main()

我的问题是,何时需要做这种事情?一些现实世界的场景?

c

115
推荐指数
3
解决办法
2万
查看次数

如何提供 memcpy 的实现

我正在尝试编写一些带有memset-style 循环的裸机代码:

for (int i = 0; i < N; ++i) {
  arr[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)

它是用 GCC 编译的,GCC 足够聪明,可以将其转换为对memset(). 不幸的是,因为它是裸机,我没有memset()(通常在 libc 中)所以我收到链接错误。

 undefined reference to `memset'
Run Code Online (Sandbox Code Playgroud)

似乎进行这种转换的优化是-ftree-loop-distribute-patterns

执行可以通过调用库生成代码的模式的循环分布。默认情况下,此标志在 -O2 及更高级别以及由-fprofile-use和启用-fauto-profile

所以一个人的解决方案是降低优化级别。不是很满意。

我还发现这真的有用的网页,说明这-ffreestanding是不足以让GCC没有做到这一点,而且也根本没有选择,只能提供自己的实现memcpymemmovememsetmemcmp。我很乐意这样做,但是怎么做?

如果我只是编写memset编译器将检测其中的循环并将其转换为对 memset 的调用!事实上,在我使用的 CPU 供应商提供的代码中,我发现了这条评论:

/*
// This is commented out because the assembly code that the compiler generates …
Run Code Online (Sandbox Code Playgroud)

c gcc memset

37
推荐指数
1
解决办法
1128
查看次数

使用Linux头文件中的unistd.h构建不带libc的静态ELF

我有兴趣使用Linux头文件提供的unistd.h构建一个没有(g)libc的静态ELF程序.

我已经阅读了这些文章/问题,这些文章/问题粗略地概括了我正在尝试做什么,但并不完全:http: //www.muppetlabs.com/~breadbox/software/tiny/teensy.html

没有libc编译

https://blogs.oracle.com/ksplice/entry/hello_from_a_libc_free

我有基本代码,它只依赖于unistd.h,其中我的理解是每个函数都是由内核提供的,而且不需要libc.这是我采取的最有希望的道路:

    $ gcc -I /usr/include/asm/ -nostdlib grabbytes.c -o grabbytesstatic
    /usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400144
    /tmp/ccn1mSkn.o: In function `main':
    grabbytes.c:(.text+0x38): undefined reference to `open'
    grabbytes.c:(.text+0x64): undefined reference to `lseek'
    grabbytes.c:(.text+0x8f): undefined reference to `lseek'
    grabbytes.c:(.text+0xaa): undefined reference to `read'
    grabbytes.c:(.text+0xc5): undefined reference to `write'
    grabbytes.c:(.text+0xe0): undefined reference to `read'
    collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

在此之前,我必须根据内核头文件中的值手动定义SEEK_END和SEEK_SET.否则就会错误地说那些没有定义,这是有道理的.

我想我需要链接到未经剥离的vmlinux来提供符号来使用.然而,我读完了符号,虽然有很多llseeks,但他们并不是llseek逐字逐句.

所以我的问题可以在几个方面:

如何指定ELF文件以使用符号?而且我猜测是否/如何可能,符号将不匹配.如果这是正确的,是否有一个现有的头文件将重新定义llseek和default_llseek或内核中的任何内容?

有没有更好的方法在没有libc的情况下在C语言中编写Posix代码?

我的目标是使用(可能只是)unistd.h编写或移植相当标准的C代码,并在没有libc的情况下调用它.我可能没有一些unistd函数,并且不确定哪些"纯粹"存在于内核调用或不存在.我喜欢集会,但这不是我的目标.希望保持尽可能严格的C(如果必须的话,我可以使用一些外部汇编文件),以便在某些时候允许无libc的静态系统.

谢谢你的阅读!

linux gcc posix libc elf

10
推荐指数
2
解决办法
2428
查看次数

是否可以在源代码中调用系统调用,而无需操作系统未附带的库?

系统调用函数由操作系统直接提供。一些库(例如GNU C库)提供包装操作系统的系统调用的函数,但操作系统不直接提供。

在Linux 中,我是否可以在C 代码中调用系统调用函数,而无需操作系统未直接提供的库(例如GNU C 库)?操作系统是否为其系统调用提供库?

例如,如果我想read()在我的C程序中直接调用系统调用函数,我应该包含哪个头文件?我必须使用一些图书馆吗?

c linux system-calls

8
推荐指数
1
解决办法
1915
查看次数

了解C运行时环境(ARM) - 从哪里开始

我是主要使用ARM Cortex-M设备的嵌入式开发人员.最近我转向Linux并决定学习更多关于构建/汇编/链接过程,如何编写makefile等,因为我正在使用IDE(IAR,Keil,Eclipse等),其中许多东西是自动化的和用户实际上并不知道后台发生了什么.目标是更多地了解这个低级别流程,如何正确使用这些工具,而不仅仅依赖于IDE默认设置.

编写完makefile后,我能够构建我的应用程序.但是,我决定通过直接调用链接器(而不是通过编译器)手动执行链接过程,并且出现了令人惊讶的麻烦!未定义的libc引用,__ libc_init_array中的_init函数,_exit等是问题所在.经过一整天的调查,我能够手动包含所有目标文件(crt0.o,crti.o)和库(libnosys.a).显然,编译器会自动执行此操作.

在克服了这些麻烦之后,我想通了,我对这些内部结构一点都不了解.为什么我需要一些ctr0.o,crti.o等.那些来自等等.它是否链接到编译器/链接器或C运行时库或系统?

我想更多地了解这些内部结构,但是,我不确定,我实际上在寻找什么.它是一个库,系统,编译器吗?

我明白,系统(MCU)需要初始化RAM中的变量和其他东西,但是我错过了完整的图片.你能指导我读一本好书/手册,关于这些东西的读物吗?我到底在想什么?

编辑:

在与您讨论后,我很可能想出了我需要的东西,所以我会按照以下方式重新解释我的问题:

1)我收到了一个MCU(假设是STM32F4xx),我应该创建一个闪烁的LED示例.所有这些都应该从头开始,自己的启动代码,没有使用外部库等.

2)在第二步中,有人告诉我所有这些已经由其他人完成(GCC工具链/标准库,MCU供应商启动文件等).所以我只需要理解/链接我的工作与完成的工作并比较差异,为什么他们这样做等等.

所有这些都是由@mbjoe回答+我发现了一些有趣的阅读:https://www.amazon.com/Embedded-Shoestring-experience-designing-software/dp/0750676094

感谢大家的帮助,并以正确的方式指导我!

c arm

8
推荐指数
1
解决办法
1557
查看次数

为什么汇编程序仅在与crt1.o crti.o和crtn.o链接时才有效?

我想知道程序是如何工作的,以便尽可能地让它成为一块骨头.

我刚刚发现了如何使用wprintf函数为x86_64汇编代码(发现宽字符是32位).我所要做的只是链接到libc(-lc).

我正在尝试为32位代码组装代码做同样的事情,但我偶然发现了一点.最终我使用gcc进行链接(并将_start:更改为main :).所以我用ld自己做了连接,包括crt1.o crti.o和crtn.o. 然后我的程序工作(之前不打印任何东西)所以我的问题是,我可以在我的代码中做些什么来消除对这些其他3个目标文件的需要(当然还原为_start:而不是main :) ?

test_lib.S

.section .data
locale:
  .string ""
  .align 4
printformat:
  .long '%','l','c',0

.section .text
.global main
main:

pushl   $locale
pushl   $6
call    setlocale
pushl   $12414
pushl   $printformat
call    wprintf
pushl   $2
call    exit
Run Code Online (Sandbox Code Playgroud)

并运行以下

as --32 test_lib.S -o test_lib.o
ld -m elf_i386 -L/lib/ -L/usr/lib/ -I/lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc /usr/lib/crtn.o test_lib.o -o test_lib
./test_lib
Run Code Online (Sandbox Code Playgroud)

哦,输出只是日本平假名(ma)ま(注意没有换行符,所以它在提示之前打印)

x86 assembly linker 32-bit

7
推荐指数
1
解决办法
1515
查看次数

如何将节从ELF输出文件映射到段?

好吧,我已经在程序集中编写了一个引导加载程序,并尝试从中加载C内核。

这是引导程序:

bits 16
xor ax,ax
jmp 0x0000:boot

extern kernel_main

global boot
boot:
    mov ah, 0x02             ; load second stage to memory
    mov al, 1                ; numbers of sectors to read into memory
    mov dl, 0x80             ; sector read from fixed/usb disk ;0 for floppy; 0x80 for hd
    mov ch, 0                ; cylinder number
    mov dh, 0                ; head number
    mov cl, 2                ; sector number
    mov bx, 0x8000           ; load into es:bx segment :offset of buffer
    int 0x13                 ; …
Run Code Online (Sandbox Code Playgroud)

x86 assembly gcc elf osdev

4
推荐指数
1
解决办法
401
查看次数

如何使用没有Glibc的C中的内联汇编来获取参数值?

如何使用没有Glibc的C中的内联汇编来获取参数值?

我需要这个代码用于Linuxarchecture x86_64i386.如果你知道MAC OS X或者Windows,也提交并请指导.

void exit(int code)
{
    //This function not important!
    //...
}
void _start()
{
    //How Get arguments value using inline assembly
    //in C without Glibc?
    //argc
    //argv
    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

新的更新

https://gist.github.com/apsun/deccca33244471c1849d29cc6bb5c78e

#define ReadRdi(To) asm("movq %%rdi,%0" : "=r"(To));
#define ReadRsi(To) asm("movq %%rsi,%0" : "=r"(To));
long argcL;
long argvL;
ReadRdi(argcL);
ReadRsi(argvL);
int argc = (int) argcL;
//char **argv = (char **) argvL;
exit(argc);
Run Code Online (Sandbox Code Playgroud)

但它仍然返回0.所以这段代码错了!请帮忙.

c assembly x86-64 i386

2
推荐指数
3
解决办法
624
查看次数

标签 统计

c ×5

assembly ×3

gcc ×3

elf ×2

linux ×2

x86 ×2

32-bit ×1

arm ×1

i386 ×1

libc ×1

linker ×1

memset ×1

osdev ×1

posix ×1

system-calls ×1

x86-64 ×1