曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5039|回复: 1
打印 上一主题 下一主题

__delay

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-1-13 09:03:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
平台:X86 32bit
内核:2.6.24
__delay() 函数用来实现一段纯延迟,它被定义在 arch/x86/lib/Delay_32.c :
void __delay(unsigned long loops)
{
    delay_fn(loops);
}

delay_fn() 同样在 arch/x86/lib/Delay_32.c 中:
static void (*delay_fn)(unsigned long) = delay_loop;

最终的实现函数是 delay_loop(),它也定义在 arch/x86/lib/Delay_32.c 中,是一段简短的汇编函数:
static void delay_loop(unsigned long loops)
{
    int d0;

    __asm__ __volatile__(
        "\tjmp 1f\n"
        ".align 16\n"
        "1:\tjmp 2f\n"
        ".align 16\n"
        "2:\tdecl %0\n\tjns 2b"
        :"=&a" (d0)
        :"0" (loops));
}
上面,
jmp 1f :跳转到 1:\tjmp 2f\n 中;

.align 16 :表示让后面的代码按照 16 字节方式对齐;

"0" (loops)
2:\tdecl %0\n\tjns 2b

%0 就是加载 loops 变量值的寄存器(可能是 %eax, 也可能是别的)。每次对寄存器中的值减 1,直到减完,即变成 -1 时,程序才结束,否则一直减 1 循环。

"=&a" (d0) :最后的结果存往 %eax 中,然后 %eax 中的值会送往 d0 变量中,如果没什么意外,d0 的最终的值为 -1 。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
沙发
 楼主| 发表于 2011-1-13 19:55:50 | 只看该作者

对 .align 对齐的一点补充

对齐是为了让处理器更高效取指,更快速的执行。我们可以照搬上面的汇编代码放在我们自己的用户程序里,以直观的方式观察编译器是如何对齐代码的。

C 代码如下
[Plain Text] 纯文本查看 复制代码
#include <stdio.h> 

static void delay_loop(unsigned long loops) 
{ 
int d0; 

__asm__ __volatile__( 
"\\tjmp 1f\\n" 
".align 16\\n" 
"1:\\tjmp 2f\\n" 
".align 16\\n" 
"2:\\tdecl %0\\n\\tjns 2b" 
:"=&a" (d0) 
:"0" (loops)); 
} 


int main() 
{ 
int loops = 10; 

delay_loop(loops); 

return (0); 
}

delay_loop 函数的反汇编代码如下
080483f0 <delay_loop>:
80483f0: 55 push %ebp
80483f1: 89 e5 mov %esp,%ebp
80483f3: 53 push %ebx
80483f4: 83 ec 10 sub $0x10,%esp
80483f7: 8b 45 08 mov 0x8(%ebp),%eax
80483fa: 89 c3 mov %eax,%ebx
80483fc: 89 d8 mov %ebx,%eax
80483fe: eb 00 jmp 8048400 <delay_loop+0x10>
8048400: eb 0e jmp 8048410 <delay_loop+0x20>
8048402: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
8048409: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
8048410: 48 dec %eax
8048411: 79 fd jns 8048410 <delay_loop+0x20>
8048413: 89 c3 mov %eax,%ebx
8048415: 89 5d f8 mov %ebx,-0x8(%ebp)
8048418: 83 c4 10 add $0x10,%esp
804841b: 5b pop %ebx
804841c: 5d pop %ebp
804841d: c3 ret
在上面的第一条 jmp 语句中,地址是 0x80483fe,它的指令码有 2 个字节。所以接下来的 jmp 指令的指令的地址是 0x80484000。原本从汇编指令中,第一条 jmp 指令过后是要对齐的,但 0x80484000 已经是个 16 字节对其的地址,所以就不需要安排对齐。

第 2 条 jmp 指令后,代码开始不对齐了。这时,编译器在中间安排进了两条 lea 指令,每条完整的指令码是 7 个字节,共 14 个字节,这样一来,我们真正需要执行的 dec %eax 的地址就落在 0x8048410 处,这个地址是个 16 字节对齐的地址。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:09 , Processed in 0.081992 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表