2016-06-03 4 views
1

후에, 나는 다음과 같은 오류 메시지가 무리를 얻을 수 내 프로그램이 돌아 가지 않을 것이라고 잘못 생각한거야? 당연히, 그것은 각각 제가 1 바이트 길이 인 배열 요소에 접근하려고하는 것과 관련이 있습니다. 다음은 프로그램 자체입니다.정크`(0,1,1) '표현

/****************************************************************************** 
*                   * 
* This program prints the string "foo" on the console.      * 
*                   * 
******************************************************************************/ 

.section .data 
    array: .byte 0x00, 0x00, 0x00, 0x00 # An array of four bytes 
    size: .int 4      # The size of the array 


.section .text 
.globl _start 
_start: 
    movb $0x66, %ah # 66 is the hexadecimal value for 'f' 
    movb $0x6F, %al # 6F is the hexadecimal value for 'o' 
    movb $0x6F, %bh # 6F is the hexadecimal value for 'o' 
    movb $0x0A, %bl # A is the hexadecimal value for '\n' 
    movb %ah, array(0, 0, 1) 
    movb %al, array(0, 1, 1) 
    movb %bh, array(0, 2, 1) 
    movb %bl, array(0, 3, 1) 

    # print 
    movl $4, %eax  # 4 is the number for the write system call 
    movl $1, %ebx  # The file descriptor to write to (1 - STDOUT) 
    movl $array, %ecx # The starting address of the string to print 
    movl size, %edx  # The number of bytes to print 
    int $0x80   # Wake up the kernel to run the write system call 

    # exit 
    movl $1, %eax  # 1 is the number for the exit system call 
    movl $0, %ebx  # Exit status code (echo $?) 
    int $0x80   # Wake up the kernel to run the exit system call 

/* 

Compile and run: 

as -gstabs test.s -o test.o && \ 
ld test.o -o a.out && \ 
rm test.o && \ 
./a.out 

*/ 
+0

필자는 손으로 작성한 asm 소스를'.s'가 아닌'.S' 파일로 유지할 것을 제안합니다. 'gcc -S test.c'는 묻지 않고'test.s'를 혼란에 빠뜨릴 것입니다. 그러나'.S'를 기본값으로 출력 파일 확장자로 사용하는 파일은 없습니다. glibc의 asm 소스 파일은 모두'.S'입니다. 또한'gcc -m32 -nostdlib test.S'로 쉽게 컴파일 할 수 있습니다. –

+0

랩탑 컴퓨터에 32 비트 리눅스가 설치되지 않았으므로 32 비트 코드를 실행하려면'-m32'가 필요합니다. 이 코드는'int 0x80' ABI가 여전히 사용 가능하기 때문에 실제로 64 비트 모드에서 작동하지만,'% rsp' 대신에'% esp'를 수정하자마자 엉망입니다. [이 대답은 64 비트 시스템에서 32 비트 코드 작성하기] 참조 (http://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain/36901649). # 36901649) 및 [x86 태그 위키]의 다른 링크 (http://stackoverflow.com/tags/x86/info) –

답변

1

매크로로 직접 빌드하지 않는 한 다차원 배열에는 asm 구문이 없습니다. 아니면 사용하지 않는 레지스터를 0(base, index, scale) 구문으로 바꾸면됩니다.

할 수있는 일은 movb $constant, array + 4과 같이 오프셋을 가져 오는 label이 포함 된 expression을 사용하는 것입니다.

컴파일러 출력을 보는 것은 구문 기본 사항부터 영리한 최적화 기법에 이르기까지, asm에서 작업하는 방법을 배우는 좋은 방법입니다. Godbolt compiler explorer에 : 그래서

#include <string.h> 
char arr[100]; // uninitialized global array 
void copy_string(){ memcpy(&arr[4], "foo\n", 4); } 

    // -O3 -fverbose-asm output: 
    movl $175075174, arr+4  #, MEM[(void *)&arr + 4B] 
    ret 

    .bss 
    .align 32 
arr: 
    .zero 100 

, arr+4는 구문입니다.movl $const, arr+4(%eax)을 작성하면 C 식 array[4 + i]과 같은 작업을 수행 할 수 있습니다. x86 주소 지정 모드의 전체 목록은 대부분 this answer을 참조하십시오 (대부분 NASM/MASM 구문이지만 실제로 중요한 것은 기계 코드에서 인코딩 할 수 있습니다). 태그 위키도 참조하십시오.


또한 알 방법 GCC puts uninitialized arrays in the .bss (보다는 .data 또는 .rodata). 즉, 실행 파일에 0 바이트가 없습니다. .bss 섹션으로 전환하는 대신 array을 선언하고 bss에서 100 바이트를 예약 할 수있는 곳에서 .comm array 100을 사용할 수도 있습니다. 단지 바로 상수는 물론 0x0a6f6f66의 것을 .bss


, 우리의 문자열을 사용에 아마 덜 혼란. gcc는 memcpy를 하나의 4 바이트 즉치 스토어에 맞게 최적화했습니다. 이후에 레지스터에 값이 남아 있지 않기 때문에. x86은 리틀 엔디안이므로 0x66 바이트는 array+0으로, 0x0aarray+3으로 들어갑니다. (GCC는하지만 방어 적이기와 이외의 별도의 좁은 매장을 병합에 짜증하며 godbolt의 링크를 참조 연타이 더 나은 것입니다..)

NASM 구문에서

, 당신이 "문자열"로 쓰기에도 수있는로 정수 상수.

movl $('f' | 'o'<<8 | 'o'<<16 | '\n'<<24), array 

GNU as 구문은 같은 손으로 쓴 ASM에 대한 친절되지 않습니다 :

mov dword [array+off], `foo\n` ;backquote for C-style \-escapes, unlike '' or "" 

GNU as은 진수 상수 + 주석보다 읽기 더 열심히 뭔가를 제외하고,이를 허용하지 않습니다 NASM/YASM,하지만 어떤면에서는 훌륭합니다. (%reg 등 쉽게 레지스터 이름이고 무엇을하지 무엇을 볼 수 있습니다.) immediate 만의


말하기 : 귀하의 size = 4이 즉시가 아닌 상수로드해야한다.

## size: .int 4 # Don't need this stored in memory anywhere 
.equ size, 4 
... 

movl $array, %ecx # The starting address of the string to print 
movl $size, %edx # The number of bytes to print 

는 또한 movl $constant, (%ecx)movl $constant, array보다 인코딩 적은 바이트를한다, 그래서 당신은 빨리 %ecx$array을 받고 다음 모드를 해결하는 간단한 레지스터를 사용하여 코드 바이트를 절약 할 수 있습니다.

2

문제는 배열 구성원을 어떻게 언급하고 있는지에 있습니다. 이것을 다음과 같이 대신 사용하십시오 :

movb %ah, array + 0 
movb %al, array + 1 
movb %bh, array + 2 
movb %bl, array + 3