在C语言中理解汇编代码

7

我正在阅读一些嵌入了几个汇编代码的C代码。我知道__asm__是一个运行汇编代码的语句,但在下面的代码中__asm__是用来做什么的呢?根据输出结果(即r = 16),似乎__asm__没有影响变量r。难道不是这样吗?

#include <stdio.h>
static void foo()
{
    static volatile unsigned int r __asm__ ("0x0019");
    r |= 1 << 4;

    printf("foo: %u\n", r);
}

平台: 在OSX Yosemite上基于LLVM 3.5svn的Apple LLVM版本6.0 (clang-600.0.56)


2
什么编译器和平台? - interjay
1
这可能意味着r是地址为0x0019的内存单元的值。 - Basile Starynkevitch
2
语法看起来有点像gcc的全局变量寄存器,尽管我只能猜测0x0019的含义。 - NPE
1
@Zilong:出于兴趣,这里的上下文是什么?那是用户空间代码吗?它是否与您的问题中所示完全相同?据您的理解,它是做什么的? - NPE
2
一种方法(如果阅读手册无法帮助)是使用-S编译并检查生成的汇编代码。尝试使用和不使用__asm__,并进行比较以了解__asm__的影响。这段代码来自哪里?上下文(您没有与我们分享)是否告诉您它应该做什么,甚至是否有任何作用? - Keith Thompson
显示剩余10条评论
1个回答

4

严格来说,你的 "asm" 代码片段只是加载一个常量(0x0019)。

以下是一个32位的例子:

#include <stdio.h>
static void foo()
{
    static volatile unsigned int r __asm__ ("0x0019");
    static volatile unsigned int s __asm__ ("0x1122");
    static volatile unsigned int t = 0x3344;
    printf("foo: %u %u %u\n", r, s, t);
}

gcc -O0 -S x.c

cat x.c
        .file   "x.c"
        .data
        .align 4
        .type   t.1781, @object
        .size   t.1781, 4
t.1781:
        .long   13124  # Note: 13124 decimal == 0x3344 hex
        .local  0x1122
        .comm   0x1122,4,4
        .local  0x0019
        .comm   0x0019,4,4
        .section        .rodata
.LC0:
        .string "foo: %u %u %u\n"
        .text
        .type   foo, @function
foo:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    t.1781, %eax
        movl    0x1122, %edx
        movl    0x0019, %ecx
        movl    %eax, 12(%esp)
        movl    %edx, 8(%esp)
        movl    %ecx, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
        leave
        ret

PS:所有基于gcc的编译器都适用“asm”语法。

PPS:我绝对鼓励您在任何地方尝试汇编语言:嵌入式系统、Ubuntu、Mac OSX-无论您喜欢什么。

这是一本很棒的书。虽然它是关于Linux的,但它也非常适用于您的OSX:

从基础开始编程,Jonathan Bartlett

另外:

https://www.hackerschool.com/blog/7-understanding-c-by-learning-assembly

http://fabiensanglard.net/macosxassembly/

PPS:x86汇编语法有两个变体:“Intel”和“ATT”语法。Gcc使用ATT。ATT语法也适用于GCC支持的任何其他架构(MIPS、PPC等等)。我建议您从ATT语法(“gcc/gas”)开始入门,而不是Intel(“nasm”)。


非常感谢。但我仍然不明白为什么gcc不能成功将其编译成可执行文件,而clang可以。我会阅读您建议的文章,并尝试理解clang生成的汇编代码。 - ZLW
嗨 - 很高兴能帮到你。不管怎样,我实际上在两个版本的GCC上编译了上面的片段(从你的代码中剪切/粘贴)。分别是32位Centos 5.5和64位CentOS 6.4。它编译("汇编" ;))得很好,但我没有尝试链接或执行任何一个版本。 - FoggyDay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接