2012-12-18 75 views
4

我想学习ARM汇编,并有一对夫妇在我的电脑生成的.s文件行被困惑我,主要是,该块:ARM汇编装载ASCII内存地址

.L6: 
    .word .LC0-(.LPIC8+4) 
    .word .LC1-(.LPIC10+4 
    .word .LC0-(.LPIC11+4) 

和它与该块:

.LCFI0: 
    ldr r3, .L6 

.LPIC8: 
    add r3, pc 

我最好的猜测告诉我,这是加载的内存地址(年初)我的ASCII字符串为R3,但我很困惑如何,这正是发生。 .LC0 - (.LPIC8 + 4)是调用add r3,pc的位置与字符串所在的位置之间的差异。将PC到这种差异应在串结束回涨,但为什么不直接调用

ldr r3, .LC0 

而不是这些.word东西和这种尴尬和LDR /增添一双?这是编译器处理这个问题的唯一或最好的方法,还是它只是编译器用来生成这样的代码的一些通用算法的结果?

此外,什么是

@ sp needed for prologue 

这听起来像编译器堆栈指针的处理增加了序幕提醒。但我觉得这应该已经发生,这不是序幕的地方..

下面是大部分汇编代码与我希望正确的评论(最后有一些调试的东西,但它包含太长。 !

任何帮助,任何人都可以提供将不胜感激

.arch armv5te 
    .fpu softvfp 
.eabi_attribute 20, 1 
.eabi_attribute 21, 1 
.eabi_attribute 23, 3 
.eabi_attribute 24, 1 
.eabi_attribute 25, 1 
.eabi_attribute 26, 2 
.eabi_attribute 30, 2 
.eabi_attribute 18, 4 
.code 16 
.file "helloneon.c" 
.section .debug_abbrev,"",%progbits 
.Ldebug_abbrev0: 
    .section .debug_info,"",%progbits 
.Ldebug_info0: 
    .section .debug_line,"",%progbits 
.Ldebug_line0: 
    .text 
.Ltext0: 
    .section .text.main,"ax",%progbits 
    .align 2 
    .global main 
    .code 16 
    .thumb_func 
    .type main, %function 
main: 
    .fnstart 
.LFB4: 
    .file 1 "jni/helloneon.c" 
    .loc 1 4 0 
    .save {r4, lr} 
    push {r4, lr} 
.LCFI0: 
    .loc 1 4 0 
    ldr r3, .L6    ; r3 = char* hello, first position 
.LPIC8: 
    add r3, pc    ; pc = program counter, r3 += pc? 
    .loc 1 3 0 
    mov r1, r3    ; r1 = r3 
    add r1, r1, #127  ; r1 += 127 
.L2: 
    .loc 1 10 0    ; r2 = holding an item in char* hello. r3 = pointer to location in hello 
    ldrb r2, [r3]  ; r2 = r3 load next char 
    sub r2, r2, #32   ; r2 -=32 subtract 32 to char in register 
    strb r2, [r3]  ; r3 = r2 put uppercase char 
    add r3, r3, #1   ; r3 += 1 
    .loc 1 8 0 
    cmp r3, r1    ; compare r3, r1 
    bne .L2     ; if not equal, goto L2 
    .loc 1 13 0 
    ldr r0, .L6+4   ; r0 = 
    ldr r1, .L6+8   ; r1 = 
    .loc 1 16 0 
    @ sp needed for prologue 
    .loc 1 13 0 
.LPIC10: 
    add r0, pc    ; r0 += pc 
.LPIC11: 
    add r1, pc    ; r1 += pc 
    bl printf    ; goto printf 
    .loc 1 16 0 
    mov r0, #0    ; r0 = 0 
    pop {r4, pc}   ; epilogue 
.L7: 
    .align 2 
.L6: 
    .word .LC0-(.LPIC8+4)  ; 
    .word .LC1-(.LPIC10+4) ; 
    .word .LC0-(.LPIC11+4) ; 
.LFE4: 
    .fnend 
    .size main, .-main 
    .section .rodata.str1.4,"aMS",%progbits,1 
    .align 2 
.LC0: 
    .ascii "helloworldthisismytestprogramtoconvertlowcharstobig" 
    .ascii "charsiamtestingneonandineedaninputofonehundredandtw" 
    .ascii "entyeightcharactersinleng\000" 
.LC1: 
    .ascii "%s\000" 
    .section .debug_frame,"",%progbits 
.Lframe0: 
    .4byte .LECIE0-.LSCIE0 
.LSCIE0: 
    .4byte 0xffffffff 
    .byte 0x1 
    .ascii "\000" 
    .uleb128 0x1 
    .sleb128 -4 
    .byte 0xe 
    .byte 0xc 
    .uleb128 0xd 
    .uleb128 0x0 
    .align 2 

和这里的C代码:

#include <stdio.h> 

int main() 
{ 
    char* hello = "helloworldthisismytestprogramtoconvertlowcharstobigcharsiamtestingneonandineedaninputofonehundredandtwentyeightcharactersinleng"; // len = 127 + \0 
    int i, size = 127; 

    for (i = 0; i < size; i++) 
    { 
     hello[i] -= 32; 
    } 

    printf("%s", hello); 

    return 0; 
} 
+0

将PIC读取为与位置无关的代码。这样你就不需要提供固定的地址。 – auselen

回答

3

ldr r3, .L6是一个伪指令。它实际上转换的内容类似ldr r3,[pc, #offset],其中offset是LDR指令与其尝试加载的值之间的内存距离。 ARM处理器的固定宽度指令意味着您只需要在LDR/STR指令中的偏移量上花费太多的位,这意味着通过PC相关负载加载的值必须存储得相当接近相应的加载指令。

.LC0.LPIC8处于完全不同的部分,因此最有可能超出PC相对负载的范围。

某些ARM汇编程序提供了一个.LTORG指令,该指令可用于在代码的同一节中分散文字的“池”。例如,这样的:

LDR r3,=.LC0 ; note the '=' 
.... 
.LTORG 

会在这样的汇编程序翻译成这样的:

LDR r3,[pc,#offset_to_LC0Value] 
.... 
LC0Value: .word .LC0 


在这个问题显示的汇编代码它不只是为PC相关的负载;正在加载的值也是PC相对的。原因是获得位置独立代码。如果绝对地址被加载然后使用,代码将会失败,除非它是从特定的虚拟地址执行的。通过相对于当前PC的地址访问所有相关数据可以让你打破这种依赖关系。

+0

旧的指令是可能仍然支持的.pool,上次我尝试过 –