GAS와 NASM 비교
Translation Log
-
07년 12월 29일
- 나름대로 번역을 하다 보니-_-a;; 원문과 다른 의미를 가지고 있는 것이 많이 존재한다. 번역된 것을 볼 때는 필히 원문과 함께 보는 것을 추천한다. ^^b 다음에도 다른 것을 번역하고 싶은데.... 쩝^^;
-
08년 1월 9일
- 일단 마무리... (정리해야 하는데.. 모르것다 ㅎㅎㅎ )
- 실행 시켜 보지 못한 예제도.. 있어 해석 이상하게 됨!!!
- 그냥 쓱~ 참고용으로만 ㅎㅎㅎ
출처 : http://www.ibm.com/developerworks/linux ··· asm.html
Linux assemblers: A comparison of GAS and NASM
A side-by-side look at GNU Assembler (GAS) and Netwide Assembler (NASM)
This article explains some of the more important syntactic and semantic differences between two of the most popular assemblers for Linux®, GNU Assembler (GAS) and Netwide Assembler (NASM), including differences in basic syntax, variables and memory access, macro handling, functions and external routines, stack handling, and techniques for easily repeating blocks of code.
Introduction
Unlike other languages, assembly programming involves understanding the processor architecture of the machine that is being programmed. Assembly programs are not at all portable and are often cumbersome to maintain and understand, and can often contain a large number of lines of code. But with these limitations comes the advantage of speed and size of the runtime binary that executes on that machine.
다 른 언어들과 다르게 어셈블리 프로그래밍은 프로그래밍이 되어지는 머신의 프로세서 아키텍쳐에 대해서 이해를 해야 한다. 어셈블리 프로그램은 거의 호환성이 존재하지 않고 그리고 이러한 것들을 유지하고 이해하는 것이 종종 귀찮을 것 이고 그리고 수많은 라인의 코드가 포함되어 있는 것을 볼 수 있을 것 입니다. 그러나 이러한 것 때문에 속도 그리고 머신에서 실행되어지는 런타임 바이너리의 사이즈에 대해서 이점을 얻게 됩니다.
Though much information is already available on assembly level programming on Linux, this article aims to more specifically show the differences between syntaxes in a way that will help you more easily convert from one flavor of assembly to the another. The article evolved from my own quest to improve at this conversion.
@ 리눅스에서의 어셈블리 레벨 프로그래밍에 대한 많은 정보가 이용할 수 있음에도 불구하고, 이 글에서는 조금 더 명확하게 하나의 좋아하는 어셈블리에서 다른 어셈블리로 조금 더 쉽게 바꿀 수 있게끔 도움을 줄 수 있는 방법에 있어서 문법들에 대한 차이점을 보여주는 것에 목표를 두고 있다.
This article uses a series of program examples. Each program illustrates some feature and is followed by a discussion and comparison of the syntaxes. Although it's not possible to cover every difference that exists between NASM and GAS, I do try to cover the main points and provide a foundation for further investigation. And for those already familiar with both NASM and GAS, you might still find something useful here, such as macros.
이 기사에서는 예제를 연속으로 사용한다. 각 프로그램은 어떤 특징에 대해서 설명을 하고 문법들의 검토(?)와 비교에 의해서 이해가 되어진다(? 설명되어진다?) NASM과 GAS 사이이의 존재하는 모든 차이점을 덮는 가능성이 없을지라도, 주된 포인트를 덮도록 시도할 것이며 더 나아가는 조사로서 토대(기초)를 제공하도록 노력을 할 것 이다. 그리고 이렇게 이미 NASM과 GAS 둘다 친근하기 때문에 여기서 당신은 여전 히 어떠한 것 예를 들면 매크로를 찾을 수 도 있다.
|
This article assumes you have at least a basic understanding of assembly terminology and have programmed with an assembler using Intel® syntax, perhaps using NASM on Linux or Windows. This article does not teach how to type code into an editor or how to assemble and link (but see the sidebar for a quick refresher). You should be familiar with the Linux operating system (any Linux distribution will do; I used Red Hat and Slackware) and basic GNU tools such as gcc and ld, and you should be programming on an x86 machine.
Now I'll describe what this article does and does not cover.
이 기사에서는 적어도 어셈블리 용어에 대해서 기본적으로 이해하고 있다고 보고 설명한다. 또한 인텔 문법을 사용하는 어셈블러나 또는 아마도 윈도우 또는 리눅스에서 NASM의 사용하는 어셈블러로 프로그램할 줄 아는 것으로 생각한다. 그리고 이 글에서는 어떻게 에디터에 코드를 넣는 것이나 또는 어떻게 어셈블 그리고 링크하는 것에 대해서 알려주지 않는다. 자 그리고 리눅스 OS에 친숙해야 합니다(어떤 리눅스 배포판이든 되는데 나는 레드햇과 슬랙웨어를 사용한다) 그리고 기본적인 GNU 툴들 예를 들면 gcc, ld 에대해서도 친숙해야 한다. 그리고 x86 머신에서 프로그래밍을 할 줄아야 한다. 지금부터 나는 이 글에서 할 것과 하지 않을 것(?)에 대해서 설명할 것 이다.
This article covers:
- Basic syntactical differences between NASM and GAS
- Common assembly level constructs such as variables, loops, labels, and macros
- A bit about calling external C routines and using functions
- Assembly mnemonic differences and usage
- Memory addressing methods
이 글에서 할 것 :
- NASM와 GAS의 기본적인 문법적인 차이점들
- 공통적인 어셈블리 레벨 구성체(?) : 예를 들면 변수, 루프, 라벨 그리고 매크로
- 외부 C 루틴을 호출하는 것과 함수를 사용하는 것에 대해서 비트(?)
- 어셈블리 니모닉 차이점과 사용 방법
- 메모리 어드레싱 방법
This article does not cover:
- The processor instruction set
- Various forms of macros and other constructs particular to an assembler
- Assembler directives peculiar to either NASM or GAS
- Features that are not commonly used or are found only in one assembler but not in the other
이 글에서 다루지 않는 것 :
프로세서의 인스트럭션 셋
-
매크로의 다양한 형태와 그리고 어셈블러에게 있어 다른 구성체에 특별하게... -_-a
-
NASM 또는 GAS가 됫든 어느한쪽에 고유의 어셈블러 디렉티브(지시어)
-
공통적으로 사용하지 않는 그리고 하나의 어셈블러에서만 찾을 수 있고 다른 어셈블러에서 찾을 수 없는 특징들
For more information, refer to the official assembler manuals (see Resources for links), as those are the most complete sources of information.
더 많은 정보를 찾기 위해서는 공식적인 어셈블러 메뉴얼을 참조하라 그리고 이러한 것들은 거의 완벽한 정보 소스들이다.
Basic structure
Listing 1 shows a very simple program that simply exits with an exit code of 2. This little program describes the basic structure of an assembly program for both GAS and NASM.
Listing1은 exit code 2를 이용하여 간단하게 exit하는 매우 간단한 프로그램을 보여준다. 이 매우 작은 프로그램은 GAS와 NASM 둘다의 어셈블리 프로그램의 기본적인 구조를 설명한다.
Listing 1. A program that exits with an exit code of 2
| Line | NASM | GAS |
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 |
; Text segment begins section .text global _start ; Program entry point _start: ; Put the code number for system call mov eax, 1 ; Return value mov ebx, 2 ; Call the OS int 80h |
# Text segment begins .section .text .globl _start # Program entry point _start: # Put the code number for system call movl $1, %eax /* Return value */ movl $2, %ebx # Call the OS int $0x80 |
Now for a bit of explanation.
One of the biggest differences between NASM and GAS is the syntax. GAS uses the AT&T syntax, a relatively archaic syntax that is specific to GAS and some older assemblers, whereas NASM uses the Intel syntax, supported by a majority of assemblers such as TASM and MASM. (Modern versions of GAS do support a directive called .intel_syntax, which allows the use of Intel syntax with GAS.)
지금부터 간단하게 설명한다(-_-a;;;)
NASM과 GAS 사이의 무자게 큰 차이점 중 하나는 문법적인 것이다. GAS는 이 것과 몇몇의 오래된 어셈블러에 특유한(독특한) 상대적으로 원시적인 문법인AT& T문법을 사용한다 그에 반하여 NASM은 대부분의 어셈블러 예를 들면 TASM과 MASM의 지지를 받는 인텔 문법을 사용한다 .(현대판 GAS는 .intel_syntax라 불리는 디렉토리르 지원하다 이 것은 GAS로 인텔 문법을 사용을 허락한다.)
The following are some of the major differences summarized from the GAS manual:
-
AT&T and Intel syntax use the opposite order for source and destination operands. For example:
- Intel:
mov eax, 4 - AT&T:
movl $4, %eax
- Intel:
-
In AT&T syntax, immediate operands are preceded by
$; in Intel syntax, immediate operands are not. For example:- Intel:
push 4 - AT&T:
pushl $4
- Intel:
- In AT&T syntax, register operands are preceded by
%; in Intel syntax, they are not. -
In AT&T syntax, the size of memory operands is determined from the last character of the opcode name. Opcode suffixes of
b,w, andlspecify byte (8-bit), word (16-bit), and long (32-bit) memory references. Intel syntax accomplishes this by prefixing memory operands (not the opcodes themselves) withbyte ptr,word ptr, anddword ptr. Thus:- Intel:
mov al, byte ptr foo - AT&T:
movb foo, %al
- Intel:
- Immediate form long jumps and calls are
lcall/ljmp $section, $offsetin AT&T syntax; the Intel syntax iscall/jmp far section:offset. The far return instruction islret $stack-adjustin AT&T syntax, whereas Intel usesret far stack-adjust.
GAS 메뉴얼에서 정리된 몇몇의 주된 차이점이 아래에 나온다
-
AT&T와 인텔 문법은 소스와 데스트네이션 오퍼런드에 대해서 반대의 순서를 사용한다. 예를 들면
- 인텔 : mov eax, 4
- AT&T : movl $4, %eax
-
AT&T 문법에서, 즉치(immediate) 오퍼런드는 $가 앞에 오고; 인텔 문법에서는 즉치(immediate) 오퍼런드는 오지 아무 것도 오지 않는다. 예를 들면
- 인텔 : push 4
- AT&T : pushl $4
- AT&T 문법에서 레지스터 오퍼런드는 %가 앞에 오고; 인텔 문법에서는 아무 것도 오지 않는다.
- AT&T 문법에서 메모리 오퍼런드의 사이즈는 오피코드(opcode) 이름의 마지막 글자에 의해 정해진다. 오피코드는 b, w를 접미사로 붙인다 그리고 나는 byte, word, long 메모리 레퍼런스를 일일이 열거한다.(번역자, 오피코드 mov에서 movb를 붙이면 byte 사이즈로 결정이 되어진다.) 인텔 문법은 byte ptr, word ptr, dword, ptr을 메모리 어퍼런드(ex, foo(?))에 접미사를 붙이는 것으로 이 것을 이룬다. (오피코드는 그것들 자체가 아닌다 ㅡㅡa)
-
AT&T 문법에서 롱 점프(jump)와 호출(call)로 부터의 즉치는 lcall/ljump $section, $offset 이다. 인텔 문법에서는 call/jmp far section:offset 이다(?). AT&T문법에서 far 리턴 인스트러럭션은 lret $stack-adjst이고 반면에 인텔은 far stack-adjst이다.
- 잘 모르겠다 ㅡㅡ;;;
In both the assemblers, the names of registers remain the same, but the syntax for using them is different as is the syntax for addressing modes. In addition, assembler directives in GAS begin with a ".", but not in NASM.
어셈블러 모두에서 레지스터의 이름은 같게 남는다(?) 그러나 이 것들을 사용하는 문법에서 차이점이 있고 또한 어드레싱 사용하는 문법에서도 차이를 보인다.게다가 GAS에서 어셈블러 디렉티브는 ".'로 시작한다. 하지만 NASM은 그렇지 않다.
The .text section is where the processor begins code execution. The global (also .globl or .global in GAS) keyword is used to make a symbol visible to the linker and available to other linking object modules. On the NASM side of Listing 1, global _start marks the symbol _start as a visible identifier so the linker knows where to jump into the program and begin execution. As with NASM, GAS looks for this _start label as the default entry point of a program. A label always ends with a colon in both GAS and NASM.
.text 섹션은 프로세스가 코드(code)의 실행이 시작되는 곳이다. 글로벌(global, 물론 GAS에서는 .globl 또는 .global) 키워드는 심볼(symbol)이 링커에게 보이게 해주는데 사용이 되어지고 또는 다른 링킹 오브젝트 모듈에게(에서..?) 이용되어지게 한다. Listing 1에서 NASM을 보면 global _start는 심볼 _start가 눈에 보이는 식별자(visible identifier-_-;;) 표시해주고 그래서 링커는 프로그램 내부로 점프해서 어디로 가야 하는지 그리고 실행이 시작되어야 하는지 알게 된다. NASM과 GAS는 프로그램의 기본 엔트리 포인트로서 이 _start 라벨을 찾는다. 라벨(주석??)은 GAS와 NASM 모두에서 항상 콜론으로 끝난다.
Interrupts are a way to inform the OS that its services are required. The int instruction in line 16 does this job in our program. Both GAS and NASM use the same mnemonic for interrupts. GAS uses the 0x prefix to specify a hex number, whereas NASM uses the h suffix. Because immediate operands are prefixed with $ in GAS, 80 hex is $0x80.
인 터럽트는 OS에게 서비스가 호출이 되어지는 것을 알려주는 방법이다. 16번째 줄에 있는 int 인스트럭션은 이 프로그램에서 이 작업(인터럽트를 이야기 하는 듯...;;)을 수행을 한다. GAS와 NASM 모두 인터럽트 사용을 위해 같은 니모닉(mnemonic)을 사용한다. GAS는 16진수를 표시하기 위해 0x를 접두사(prefix. 프리픽스)로 사용한다. 반면에 NASM은 h를 접미사(suffix)로 사용한다. 왜냐하면 즉치(immediate ) 오퍼런드는 GAS에서 $ 뒤에 놓여지기 때문이다. 16진수 80은 $0x80으로 표시된다.
int $0x80 (or 80h in NASM) is used to invoke Linux and request a service. The service code is present in the EAX register. A value of 1 (for the Linux exit system call) is stored in EAX to request that the program exit. Register EBX contains the exit code (2, in our case), a number that is returned to the OS. (You can track this number by typing echo $? at the command prompt.)
int $0x80(또는 NASM에서 80h)는 리눅스의 기능(핵심?)을 사용하는데 되어지고 또는 서비스를 호출하는데 사용되어 진다. 서비스 코드(service code)는 EAX 레지스터에 표시한다. 값 1 (이 값은 리눅스에서 exit 시스템 콜이다)은 EAX 레지스터에 프로그램의 종료를 요청하기 위해서 저장한다. 레지스터 EBX에는 exit code를 포함한다(우리의 경우 2, 궁금? 이 것이 리턴값-.-a) 이 숫자는 OS에 리턴되어 진다.(이 숫자를 커맨드 프롬포트에서 echo $?로 추적을 할 수 있다.)
Finally, a word about comments. GAS supports both C style (/* */), C++ style (//), and shell style (#) comments. NASM supports single-line comments that begin with the ";" character.
마침내, 코맨트에 대한 말을 하게 되는 구나~ GAS에서는 C 스타일(/* *), C++ 스타일(//), 그리고 쉘 스타일(#) 커맨트 모두를 지원한다. NASM은 ";' 문자로 시작하는 싱글 라인 코맨트를 지원한다.
Variables and accessing memory
This section begins with an example program that finds the largest of three numbers.
이 섹션은 3개의 숫자 중에서 무자게 큰 숫자를 찾는 예제 프로그램으로 시작한다. (이런거 해석하기 힘들다-_-;; )
Listing 2. A program that finds the maximum of three numbers
| Line | NASM | GAS |
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 |
; Data section begins section .data var1 dd 40 var2 dd 20 var3 dd 30 section .text global _start _start: ; Move the contents of variables mov ecx, [var1] cmp ecx, [var2] jg check_third_var mov ecx, [var2] check_third_var: cmp ecx, [var3] jg _exit mov ecx, [var3] _exit: mov eax, 1 mov ebx, ecx int 80h |
// Data section begins .section .data var1: .int 40 var2: .int 20 var3: .int 30 .section .text .globl _start _start: # move the contents of variables movl (var1), %ecx cmpl (var2), %ecx jg check_third_var movl (var2), %ecx check_third_var: cmpl (var3), %ecx jg _exit movl (var3), %ecx _exit: movl $1, %eax movl %ecx, %ebx int $0x80 |
You can see several differences above in the declaration of memory variables. NASM uses the dd, dw, and db directives to declare 32-, 16-, and 8-bit numbers, respectively, whereas GAS uses the .long, .int, and .byte for the same purpose. GAS has other directives too, such as .ascii, .asciz, and .string. In GAS, you declare variables just like other labels (using a colon), but in NASM you simply type a variable name (without the colon) before the memory allocation directive (dd, dw, etc.), followed by the value of the variable.
위의 메모리 변수 선언에서 몇몇의 차이점을 볼 수 있을 것 이다. NASM은 각각 32비트, 16비트, 그리고 8비트를 선언하기 위해서 dd, dw 그리고 db 디렉티브 사용한다. 반면에 GAS는 각 목적을 달성하기 위해서 .long, .int 그리고 .byte를 사용한다. GAS 는 역시 .ascii, .asciz, 그리고 .string와 같은 다른 디렉티브(directives)를 가지고 있다. GAS에서 다른 라벨(lable, 콜론을 사용해서)을 사용하는 것 처럼 변수를 선언한다. 그러나 NASM에서는 변수의 값이 뒤에 따라는 메모리 할당 디렉티브(dd, dw, 기타 등등) 앞에 변수이름을 사용함으로써 간단하게 선언할 수 있다.(말이 복잡해서 그렇지 "변수이름" "데이터 타입" "값" 이렇게 온다는 이야기 ㅡ.ㅡ;;)
Line 18 in Listing 2 illustrates the memory indirect addressing mode. NASM uses square brackets to dereference the value at the address pointed to by a memory location: [var1]. GAS uses a circular brace to dereference the same value: (var1). The use of other addressing modes is covered later in this article.
온Listing 2에서 18번째 줄은 메모리 간접 어드레싱 모드(indirect addressing mode)를 설명한다. NASM은 메모리 로케이션 [var1]에 의해 포인트되어진 주소에 있는 값을 디레퍼런스(번지에 있는 실제 값에 접근)하기 위해서 square brackets( []를 말하는 듯;;)를 사용한다. GAS는 circular brace( ()를 말하는 듯...)를 이용하여 같은 값 (var1)의 값을 얻는다. 다른 어드레싱 모드들에 대한 사용은 이 글에서 나중에 이야기한다.
Using macros##
Listing 3 illustrates the concepts of this section; it accepts the user's name as input and returns a greeting.
Listing3은 이 세션의 컨셉 - 유저의 이름을 입력 받고 인사(?)를 리턴하는 - 을 설명한다.
Listing 3. A program to read a string and display a greeting to the user
| Line | NASM | GAS |
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 |
section .data prompt_str db 'Enter your name: ' ; $ is the location counter STR_SIZE equ $ - prompt_str greet_str db 'Hello ' GSTR_SIZE equ $ - greet_str section .bss ; Reserve 32 bytes of memory buff resb 32 ; A macro with two parameters ; Implements the write system call %macro write 2 mov eax, 4 mov ebx, 1 mov ecx, %1 mov edx, %2 int 80h %endmacro ; Implements the read system call %macro read 2 mov eax, 3 mov ebx, 0 mov ecx, %1 mov edx, %2 int 80h %endmacro section .text global _start _start: write prompt_str, STR_SIZE read buff, 32 ; Read returns the length in eax push eax ; Print the hello text write greet_str, GSTR_SIZE pop edx ; edx = length returned by read write buff, edx _exit: mov eax, 1 mov ebx, 0 int 80h |
.section .data prompt_str: .ascii "Enter Your Name: " pstr_end: .set STR_SIZE, pstr_end - prompt_str greet_str: .ascii "Hello " gstr_end: .set GSTR_SIZE, gstr_end - greet_str .section .bss // Reserve 32 bytes of memory .lcomm buff, 32 // A macro with two parameters // implements the write system call .macro write str, str_size movl $4, %eax movl $1, %ebx movl \str, %ecx movl \str_size, %edx int $0x80 .endm // Implements the read system call .macro read buff, buff_size movl $3, %eax movl $0, %ebx movl \buff, %ecx movl \buff_size, %edx int $0x80 .endm .section .text .globl _start _start: write $prompt_str, $STR_SIZE read $buff, $32 // Read returns the length in eax pushl %eax // Print the hello text write $greet_str, $GSTR_SIZE popl %edx // edx = length returned by read write $buff, %edx _exit: movl $1, %eax movl $0, %ebx int $0x80 |
The heading for this section promises a discussion of macros, and both NASM and GAS certainly support them. But before we get into macros, a few other features are worth comparing.
이 섹션의 제목은 매크로에 대해서 이야기할 것이라 약속을 한다. 그리고 NASM과 GAS 모두 확실히 매크로를 지원한다. 그러나 매크로를 시작하기 전에 몇몇의 다른 특징들은 가치있는 비교가 된다.(어색;;;)
Listing 3 illustrates the concept of uninitialized memory, defined using the .bss section directive (line 14). BSS stands for "block storage segment" (originally, "block started by symbol"), and the memory reserved in the BSS section is initialized to zero during the start of the program. Objects in the BSS section have only a name and a size, and no value. Variables declared in the BSS section don't actually take space, unlike in the data segment.
Listing 3은 14번째 줄에 .bss 섹션 디렉티브의 사용으로 정의된 초기화되지 않은 메모리 컨셉에 대해서 설명한다. BSS는 "block storage segment"(원래는 "block started by symbol")를 의미한다. 그리고 BSS 섹션에 예약된 메모리는 프로그램이 시작하는 동안 0으로 초기화된다. BSS 섹션에서 오브젝트들은 단지 이름과 크기 그리고 값이 없는 상태를 가진다. BSS 섹션에 선언된 변수는 데이타 세그먼트와 다르게 실제로 공간을 차지하지 않는다.
NASM uses the resb, resw, and resd keywords to allocated byte, word, and dword space in the BSS section. GAS, on the other hand, uses the .lcomm keyword to allocate byte-level space. Notice the way the variable name is declared in both versions of the program. In NASM the variable name precedes the resb (or resw or resd) keyword, followed by the amount of space to be reserved, whereas in GAS the variable name follows the .lcomm keyword, which is then followed by a comma and then the amount of space to be reserved. This shows the difference:
NASM는 BSS섹션에서 byte, word, 그리고 dword 크기의 공간을 할당하기 위해서 resb, resw 그리고 resd 키워드를 사용한다. 반 면에 GAS는 .lcomm 키워드르를 이용하여 바이트-레벨 공간을 할당한다.(GAS는 무조건 byte 단위 할당인가?;;;) Notice(어떻게 해야 하나;;;) 변수의 이름은 두 프로그램 버젼에서 선언되어 진다. NASM에서 변수 이름은 많은 예약된 공간을 가지는 resb(또는 resw 또는 resd) 키워드 앞에 오게되고, 반면에 GAS에서 변수 이름은 .lcomm 키워드뒤에 오게되고 이 것은 이 때 콤마(,)에 의해서 구분이 되고 그리고 또 많은 양의 예약된 공간이 오게 된다. 아래는 차이점을 보여주고 있다.
NASM: varname resb size (변수이름 키워드 사이즈)
GAS: .lcomm varname, size (키워드 변수이름, 사이즈)
Listing 2 also introduces the concept of a location counter (line 6). NASM provides a special variable (the $ and $$ variables) to manipulate the location counter. In GAS, there is no method to manipulate the location counter and you have to use labels to calculate the next storage location (data, instruction, etc.).
Listing3(원문 오타인듯 싶음...;;;)는 6번째 줄에서 로케이션 카운터(현재의 위치를 알려주는 키워드???) 의 컨셉을 소개하고 있다. NASM은 로케이션 카운터를 다루기 위해서 특별한 변수($ 와 $$ 변수)를 제공한다. GAS에서는 로케이션 카운터를 조작하기 위한 방법이 없고 다음 저장 위치(data, instruction, 기타)를 계산하기 위해서레이블(lable)을 사용해야 한다.
For example, to calculate the length of a string, you would use the following idiom in NASM:
예를 들면, 스트링의 길이를 계산하기 위해서, NASM에서는 아래에 나오는 표현형식을 사용해야 한다.
prompt_str db 'Enter your name: '
STR_SIZE equ $ - prompt_str ; $ is the location counter
The $ gives the current value of the location counter, and subtracting the value of the label (all variable names are labels) from this location counter gives the number of bytes present between the declaration of the label and the current location. The equ directive is used to set the value of the variable STR_SIZE to the expression following it. A similar idiom in GAS looks like this:
$는 현재의 로케이션 카운터 값을 준다(i think, 현재 위치의 오프셋 정도를 리턴한다???) 로케이션 카운터에서 라벨(모든 변수의 이름은 라벨이다) 값을 빼는 것은 라벨의 선언과 현재 위치(대 략 어디쯤?? $ 가 있는 곳을 말하는 건가?) 사이에 존재하는 바이트 수를 넘겨주게 된다. equ 디렉티브는 변수 STR_SIZE의 값을 그에 뒤 따루는 수식을 셋팅하는데 사용이 되어진다. GAS에서 유사한 표현형식은 아래를 보시라^^;
prompt_str:
.ascii "Enter Your Name: "
pstr_end:
.set STR_SIZE, pstr_end - prompt_str
The end label (pstr_end) gives the next location address, and subtracting the starting label address gives the size. Also note the use of .set to initialize the value of the variable STR_SIZE to the expression following the comma. A corresponding .equ can also be used. There is no alternative to GAS's set directive in NASM.
끝에 있는 라벨 pstr_end 다음 로케이션 주소(?)를 제공한다. 시작하는 라벨 주소를 빼는 것은 사이즈를 준다.(?) 물론 변수 STR_SIZE의 값을 콤마에 뒤 따루는 수식을 초기화하기 위해서 .set를 사용한다는 것도 생각해보자. 유사한 .equ는 물론 사용이 되어질 수 있다(.set 와 비슷하다는 이야기???). NASM에서 GAS 셋 디렉티브를 대체할 것이 없다. (-_-아 힘들다... ㅡㅜ)
As I mentioned, Listing 3 uses macros (line 21). Different macro techniques exist in NASM and GAS, including single-line macros and macro overloading, but I only deal with the basic type here. common use of macros in assembly is clarity. Instead of typing the same piece of code again and again, you can create reusable macros that both avoid this repetition and enhance the look and readability of the code by reducing clutter.
내가 말한 것 처럼;; Listing 3의 21번째 줄에서 매크로를 사용한다. NASM과 GAS에서 다른 매크로 기법이 존재하고 싱글라인 매크로와 매크로 오버로딩을 포함한다. 그러나 나는 여기에서 단지 기본적인 타입만 다룬다. 어셈블리에서 공통된 매크로의 사용은 명쾌하다. 같은 코드의 조각을 재사용하는 대신에 이러한 반복을 회피하고 그리고 어지럽게 흩어져 있는 것을 줄임으로서 코드를 보기 좋게 그리고 가독성을 올리는 재사용 할 수 있는 매크로를 만들어서 사용할 수 있다.
NASM users might be familiar with declaring macros using the %beginmacro directive and ending them with an %endmacro directive. A %beginmacro directive is followed by the macro name. After the macro name comes a count, the number of macro arguments the macro is supposed to have. In NASM, macro arguments are numbered sequentially starting with 1. That is, the first argument to a macro is %1, the second is %2, the third is %3, and so on. For example:
NASM 사용자는 %beginmacro 디렉티브 사용과 %endmacro 디렉티브로 끝나는 매크로를 설명하는데 친숙할지도 모른다. %beginmarco 디렉티브 뒤에는 매크로 이름이 자리를 잡는다. 매크로 이름 다음에 총수가 온 후에 매크로 아규먼트의 수는 가지게될 것으로 되어 있다-_-;;; NASM에서 매크로 어규먼트는 1부터 순차적으로 번호가 매겨진다. 즉 매크로의 첫번째 어규먼트는 %1, 두번째는 %2, 세번째는 %3, 기타 등등 예를 들면 아래와 같다.
%beginmacro macroname 2
mov eax, %1
mov ebx, %2
%endmacro
This creates a macro with two arguments, the first being %1 and the second being %2. Thus, a call to the above macro would look something like this:
이 것은 2개의 아규먼트를 가지는 매크로를 만든다. 첫번째는 %1, 두번째는 %2. 이와 같이 위의 매크로 콜은 아래와 같이 어떤한 것 처럼 보일 수 있다.
macroname 5, 6
Macros can also be created without arguments, in which case they don't specify any number.
매크로는 물론 아규먼트 없이 만들어 질 수 있다. 이러한 경우 그것들은 어떠한 숫자도 명시하지 않는다.
Now let's take a look at how GAS uses macros. GAS provides the .macro and .endm directives to create macros. A .macro directive is followed by a macro name, which may or may not have arguments. In GAS, macro arguments are given by name. For example:
GAS는 어떻게 매크로를 사용하지는 한번 보자. GAS는 .macro와 .endm 디렉티브를 매크로를 만들기 위해서 제공한다. .macro 디렉티브 다음에 매크로 이름이 뒤 따르고 아규먼트를 가질 수도 가지지 않을 수 도 있다. GAS에서 매크로 아규먼트를 이름에 의해서 주어진다. 아래의 예를 보시라!!!
.macro macroname arg1, arg2
movl \arg1, %eax
movl \arg2, %ebx
.endm
A backslash precedes the name of each argument of the macro when the name is actually used inside a macro. If this is not done, the linker would treat the names as labels rather then as arguments and will report an error.
이름(아규먼트?)이 실제로 매크로 안쪽에서 사용되어 질 때 백슬래쉬 다음에는 매크로의 각 아규먼트의 이름이 오게된다.만약 이것이 그렇게 되지 않으면, 링커는 이름들을 아규먼트로서가 아니라 라벨로서 조작할 것이며 에어를 보고할 것 이다.
Functions, external routines, and the stack
The example program for this section implements a selection sort on an array of integers.
이 셕션에서 예제 프로그램은 정수 배열의 선택 정렬을 실행한다.
Listing 4. Implementation of selection sort on an integer array
| Line | NASM | GAS |
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
section .data array db 89, 10, 67, 1, 4, 27, 12, 34, 86, 3 ARRAY_SIZE equ $ - array array_fmt db " %d", 0 usort_str db "unsorted array:", 0 sort_str db "sorted array:", 0 newline db 10, 0 section .text extern puts global _start _start: push usort_str call puts add esp, 4 push ARRAY_SIZE push array push array_fmt call print_array10 add esp, 12 push ARRAY_SIZE push array call sort_routine20 ; Adjust the stack pointer add esp, 8 push sort_str call puts add esp, 4 push ARRAY_SIZE push array push array_fmt call print_array10 add esp, 12 jmp _exit extern printf print_array10: push ebp mov ebp, esp sub esp, 4 mov edx, [ebp + 8] mov ebx, [ebp + 12] mov ecx, [ebp + 16] mov esi, 0 push_loop: mov [ebp - 4], ecx mov edx, [ebp + 8] xor eax, eax mov al, byte [ebx + esi] push eax push edx call printf add esp, 8 mov ecx, [ebp - 4] inc esi loop push_loop push newline call printf add esp, 4 mov esp, ebp pop ebp ret sort_routine20: push ebp mov ebp, esp ; Allocate a word of space in stack sub esp, 4 ; Get the address of the array mov ebx, [ebp + 8] ; Store array size mov ecx, [ebp + 12] dec ecx ; Prepare for outer loop here xor esi, esi outer_loop: ; This stores the min index mov [ebp - 4], esi mov edi, esi inc edi inner_loop: cmp edi, ARRAY_SIZE jge swap_vars xor al, al mov edx, [ebp - 4] mov al, byte [ebx + edx] cmp byte [ebx + edi], al jge check_next mov [ebp - 4], edi check_next: inc edi jmp inner_loop swap_vars: mov edi, [ebp - 4] mov dl, byte [ebx + edi] mov al, byte [ebx + esi] mov byte [ebx + esi], dl mov byte [ebx + edi], al inc esi loop outer_loop mov esp, ebp pop ebp ret _exit: mov eax, 1 mov ebx, 0 int 80h |
.section .data array: .byte 89, 10, 67, 1, 4, 27, 12, 34, 86, 3 array_end: .equ ARRAY_SIZE, array_end - array array_fmt: .asciz " %d" usort_str: .asciz "unsorted array:" sort_str: .asciz "sorted array:" newline: .asciz "\n" .section .text .globl _start _start: pushl $usort_str call puts addl $4, %esp pushl $ARRAY_SIZE pushl $array pushl $array_fmt call print_array10 addl $12, %esp pushl $ARRAY_SIZE pushl $array call sort_routine20 # Adjust the stack pointer addl $8, %esp pushl $sort_str call puts addl $4, %esp pushl $ARRAY_SIZE pushl $array pushl $array_fmt call print_array10 addl $12, %esp jmp _exit print_array10: pushl %ebp movl %esp, %ebp subl $4, %esp movl 8(%ebp), %edx movl 12(%ebp), %ebx movl 16(%ebp), %ecx movl $0, %esi push_loop: movl %ecx, -4(%ebp) movl 8(%ebp), %edx xorl %eax, %eax movb (%ebx, %esi, 1), %al pushl %eax pushl %edx call printf addl $8, %esp movl -4(%ebp), %ecx incl %esi loop push_loop pushl $newline call printf addl $4, %esp movl %ebp, %esp popl %ebp ret sort_routine20: pushl %ebp movl %esp, %ebp # Allocate a word of space in stack subl $4, %esp # Get the address of the array movl 8(%ebp), %ebx # Store array size movl 12(%ebp), %ecx decl %ecx # Prepare for outer loop here xorl %esi, %esi outer_loop: # This stores the min index movl %esi, -4(%ebp) movl %esi, %edi incl %edi inner_loop: cmpl $ARRAY_SIZE, %edi jge swap_vars xorb %al, %al movl -4(%ebp), %edx movb (%ebx, %edx, 1), %al cmpb %al, (%ebx, %edi, 1) jge check_next movl %edi, -4(%ebp) check_next: incl %edi jmp inner_loop swap_vars: movl -4(%ebp), %edi movb (%ebx, %edi, 1), %dl movb (%ebx, %esi, 1), %al movb %dl, (%ebx, %esi, 1) movb %al, (%ebx, %edi, 1) incl %esi loop outer_loop movl %ebp, %esp popl %ebp ret _exit: movl $1, %eax movl 0, %ebx int $0x80 |
Listing 4 might look overwhelming at first, but in fact it's very simple. The listing introduces the concept of functions, various memory addressing schemes, the stack and the use of a library function. The program sorts an array of 10 numbers and uses the external C library functions puts and printf to print out the entire contents of the unsorted and sorted array. For modularity and to introduce the concept of functions, the sort routine itself is implemented as a separate procedure along with the array print routine. Let's deal with them one by one.
Listing4는 처음에 보면 굉장하게 보일 수도 있다. 그러나 사실 이것은 매우 간단하다-_-;;. 리스팅은 함수와 다양한 메모리 어드레싱 스키마 그리고 스택 그리고 라이브러리 함수의 사용에 대한 컨셉을 소개한다. 프 로그램은 10개의 숫자들로된 배열을 정렬하고 외부(external) C 라이브러리 함수 puts 그리고 정렬되지 않은 그리고 정렬된 배열의 전체 내용을 보기 위하여 printf를 사용한다. 모듈성을 위해서 그리고 함수의 컨셉을 소개하기 위해서 정렬 루틴 자체는 배열 출력 루틴과는 떨어져서 함수로서 구현되었다. 이 것들을 하나 하나 다루어 보자! @ 약간...--a @
After the data declarations, the program execution begins with a call to puts (line 31). The puts function displays a string on the console. Its only argument is the address of the string to be displayed, which is passed on to it by pushing the address of the string in the stack (line 30).
데이타 선언 후에 프로그램의 실행은 31번째 줄에 있는 puts를 호출하는 것으로 시작한다. puts 함수는 콘솔에 스트링을 출력한다. 출력이 되어지는 스트링의 주소는 단지 아규먼트이다. 30번째 줄에 스택에 스트링의 주소를 푸싱하는 것으로서이 것을 이루어지게 된다(함수의 인자로서 스택에 스트링의 주소를 넣는다)
In NASM, any label that is not part of our program and needs to be resolved during link time must be predefined, which is the function of the extern keyword (line 24). GAS doesn't have such requirements. After this, the address of the string usort_str is pushed onto the stack (line 30). In NASM, a memory variable such as usort_str represents the address of the memory location itself, and thus a call such as push usort_str actually pushes the address on top of the stack. In GAS, on the other hand, the variable usort_str must be prefixed with $, so that it is treated as an immediate address. If it's not prefixed with $, the actual bytes represented by the memory variable are pushed onto the stack instead of the address.
NASM에서 링크 타임 동안에 우리 프로그램의 부분으로서가 아닌 그리고 해결이 되어질 필요가 있는 어떤 라벨이든 미리 정의가 되어져야 한다. 24번째 줄에서 extern 함수 키워드를 말할 수 있다????(-_-a, 예...aa) GAS는 그러한 요구들을 하지 않는다. 이렇게 한 후 30번째줄에 나와있는 것 처럼 usort_str 스트링의 주소는 스택에 푸쉬된다. NASM에서는 메모리 변수 즉 usort_str 이러한 것은 자체는 메모리 로케이션(위치)의 주소로 표현이 된다. 그래서 실제로 push usort_str 의 콜은 스택의 탑에 주소를 푸쉬한다. GAS에서는 반대로 변수 usort_str는 $가 앞에 붙게 된다. 그래서 즉치주소로서 다루어지게 된다. 만약 $가 없으면, 메모리 주소에 의해서 표현이 되는 실제 바이트는 주소대신에 스택에 푸쉬된다. (쩝-_-내용 정리 안되네;;;)
Since pushing a variable essentially moves the stack pointer by a dword, the stack pointer is adjusted by adding 4 (the size of a dword) to it (line 32).
본래 변수를 푸싱하는 것은 dword 크기로 스택 포인터를 이동하기 때문에, 스택포인터는 4(dword의 사이즈, 32번째 줄)를 더하는 것으로 맞춰진다.
Three arguments are now pushed onto the stack, and the print_array10 function is called (line 37). Functions are declared the same way in both NASM and GAS. They are nothing but labels, which are invoked using the call instruction.
3개의 아규먼트는 지금 스택에 푸쉬된다. 그리고 37번째 출에서 print_array10 함수는 호출되어진다. 함수는 NASM이나 GAS 모두에서 같은 방법으로 선언한다. 이러한 것은 아무 것도 아니지만-_-a 라벨인데 이것은 call 인스트럭션을 사용하는 것으로 다루어진다.(해석이란....)
After a function call, ESP represents the top of the stack. A value of esp + 4 represents the return address, and a value of esp + 8 represents the first argument to the function. All subsequent arguments are accessed by adding the size of a dword variable to the stack pointer (that is, esp + 12, esp + 16, and so on).
함수를 호출 후에 ESP는 스택의 탑에 놓이게 되고, esp + 4의 값은 리턴주소를 나타내고, 그리고 esp + 8의 값은 함수의 첫번째 아규먼트를 나타낸다. 다음의 모든 아규먼트는 dword 변수의 사이즈와 스택 포인터를 더 함으로써 접근한다.(즉, esp + 12, esp + 16, 기타 등등)
Once inside a function, a local stack frame is created by copying esp to ebp (line 62). You can also allocate space for local variables as is done in the program (line 63). You do this by subtracting the number of bytes required from esp. A value of esp – 4 represents a space of 4 bytes allocated for a local variable, and this can continue as long as there is enough space in the stack to accommodate your local variables.
한번 함수의 안쪽을 보게되면, 62번째 줄에서 로컬 스택 프레임은 esp에서 ebp로 복사되어 만들어진다. 63번째 줄에서 수행이 되고 나고 나면 지역변수를 위한 공간을 할당 할 수 있다. 그리고 esp에서 요구하는 바이트 수 만큼 뽑아내어서 이 것을 한다.;;; esp -4의 값은 지역변수를 위해 할당된 4바이트 공간으로 나타낸다. 그리고 스택에 지역변수를 수용할 수 있는 충분한 공간이 있다면 이 것은 계속 할 수 있다.
Listing 4 illustrates the base indirect addressing mode (line 64), so called because you start with a base address and add an offset to it to arrive at a final address. On the NASM side of the listing, [ebp + 8] is one such example, as is [ebp – 4] (line 71). In GAS, the addressing is a bit more terse: 4(%ebp) and -4(%ebp), respectively.
Listing4에서 64번째 줄을 보면 베이스(?) 간접 어드레싱을 설명한다. so called(?) 베이스 어드레스로 시작하고 그리고 오프셋과 이 어드레스를 목적 어드레스를 얻기 위해서 더한다. 리스팅에서 NASM을 보게되면 [ebp + 8]은 하나의 예이고 그리고 71번째 줄에서 [ebp - 4]도 그렇다. GAS에서 어드레싱은 좀 더 간결하게 처리한다 : 각각 4(%ebp) 그리고 -4(%ebp)
In the print_array10 routine, you can see another kind of addressing mode being used after the push_loop label (line 74). The line is represented in NASM and GAS, respectively, like so:
@ print_array10 루틴을 보게되면 74번째 줄에서 push_loop 라벨 후에 사용되어지는 다른 종류의 어드레싱 모드를 볼 수 있을 것이다. 이 줄은 각각 NASM, GAS에서 아래와 같이 쓰인다(후후.. 내 맘 해석-_-)
NASM: mov al, byte [ebx + esi]
GAS: movb (%ebx, %esi, 1), %al
This addressing mode is the base indexed addressing mode. Here, there are three entities: one is the base address, the second is the index register, and the third is the multiplier. Because it's not possible to determine the number of bytes to be accessed from a memory location, a method is needed to find out the amount of memory addressed. NASM uses the byte operator to tell the assembler that a byte of data is to be moved. In GAS the same problem is solved by using a multiplier as well as using the b, w, or l suffix in the mnemonic (for example, movb). The syntax of GAS can seem somewhat complex when first encountered.
이 어드레싱 모드는 base indexed 어드레싱 모드이다. 여기에서는 3가지의 어떠한 것이 나올 수 있다: 첫째 : 베이스 어드레스, 두번째 : 인덱스 레지스터, 세번째 : multiplier. 메모리 로케이션로 부터 접근이되어지는 바이트 수만큼에 의해 결정되는 것이 불가능하기 때문에-- 많은 양의 주소화된 메모리를 찾아지는 방법이다-_-;; NASM에서 어셈블러에게 바이트 크기의 데이타가 이동되어지는 것을 전달하기 위해 바이트 오퍼레이터를 사용한다. GAS에서는 multiplier 뿐만 아니라 b, w, | 등(예를 들면 movb)을 사용함으로써 같은 문제를 해결한다. GAS 문법은 처음에 만나면 다소 복잡해 보일 수 있다.
The general form of base indexed addressing in GAS is as follows:
GAS에서 base indexed 어드레싱의 일반전인 형태는 아래와 같다
%segment:ADDRESS (, index, multiplier) or %segment:(offset, index, multiplier) or %segment:ADDRESS(base, index, multiplier)
The final address is calculated using this formula:
최종 주소는 이 공식을 이용해서 계산된다.
ADDRESS or offset + base + index * multiplier.
Thus, to access a byte, a multiplier of 1 is used, for a word, 2, and for a dword, 4. Of course, NASM uses a simpler syntax. Thus, the above in NASM would be represented like so:
이라하여 바이트에 접근한기 위해서 , 1의 multiplier 사용되어 지고, word 그리고 2 그리고 dword, 4 -_-a NASM은 간단한 문법을 사용한다 이와 같이 NASM에서 위에 것은 아래와 같이 표현이 된다.
Segment:[ADDRESS or offset + index * multiplier]
A prefix of byte, word, or dword is used before this memory address to access 1, 2, or 4 bytes of memory, respectively
메모리의 각각 1,2,4byte에 접근하기 위한 메모리 주소 전에 byte, word, dword의 프리픽스는 사용되어 진다. (흠...-- )
Leftovers
Listing 5 reads a list of command line arguments, stores them in memory, and then prints them.
Listing5는 커맨드 라인 아규먼트를 읽고, 메모리에 그 것을들을 저장하고 화면에 출력한다.
Listing 5. A program that reads command line arguments, stores them in memory, and prints them
| Line | NASM | GAS |
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 |
section .data ; Command table to store at most ; 10 command line arguments cmd_tbl: %rep 10 dd 0 %endrep section .text global _start _start: ; Set up the stack frame mov ebp, esp ; Top of stack contains the ; number of command line arguments. ; The default value is 1 mov ecx, [ebp] ; Exit if arguments are more than 10 cmp ecx, 10 jg _exit mov esi, 1 mov edi, 0 ; Store the command line arguments ; in the command table store_loop: mov eax, [ebp + esi * 4] mov [cmd_tbl + edi * 4], eax inc esi inc edi loop store_loop mov ecx, edi mov esi, 0 extern puts print_loop: ; Make some local space sub esp, 4 ; puts function corrupts ecx mov [ebp - 4], ecx mov eax, [cmd_tbl + esi * 4] push eax call puts add esp, 4 mov ecx, [ebp - 4] inc esi loop print_loop jmp _exit _exit: mov eax, 1 mov ebx, 0 int 80h |
.section .data // Command table to store at most // 10 command line arguments cmd_tbl: .rept 10 .long 0 .endr .section .text .globl _start _start: // Set up the stack frame movl %esp, %ebp // Top of stack contains the // number of command line arguments. // The default value is 1 movl (%ebp), %ecx // Exit if arguments are more than 10 cmpl $10, %ecx jg _exit movl $1, %esi movl $0, %edi // Store the command line arguments // in the command table store_loop: movl (%ebp, %esi, 4), %eax movl %eax, cmd_tbl( , %edi, 4) incl %esi incl %edi loop store_loop movl %edi, %ecx movl $0, %esi print_loop: // Make some local space subl $4, %esp // puts functions corrupts ecx movl %ecx, -4(%ebp) movl cmd_tbl( , %esi, 4), %eax pushl %eax call puts addl $4, %esp movl -4(%ebp), %ecx incl %esi loop print_loop jmp _exit _exit: movl $1, %eax movl $0, %ebx int $0x80 |
Listing 5 shows a construct that repeats instructions in assembly. Naturally enough, it's called the repeat construct. In GAS, the repeat construct is started using the .rept directive (line 6). This directive has to be closed using an .endr directive (line 8). .rept is followed by a count in GAS that specifies the number of times the expression enclosed inside the .rept/.endr construct is to be repeated. Any instruction placed inside this construct is equivalent to writing that instruction count number of times, each on a separate line.
Listing5는 어셈블리에서 인스트럭션이 반복적으로 사용되어지는 구성개념(?)을 보여준다. ... 이 것은 반복되는 구성개념이라 불린다. GAS에서 반복되는 구성개념은 6번째 줄에서 보는 것 처럼 .rept 디렉티브를 사용하는 것으로 시작된다. 이 디렉티브는 8번째 줄에서 보는 것 처럼 .endr 디렉티를 사용함으로 사용이 끝나게 된다. .rept는 GAS에서 숫자(?, 인자를 말하는 듯... 반복횟수 정도)에 의해 진행이 되어진다. This directive has to be closed using an .endr directive (line 8). .rept is followed by a count in GAS that specifies the number of times the expression enclosed inside the .rept/.endr construct is to be repeated. 이 구성개념 안쪽에 놓여지는 각 라인에 있는 어떠한 인스트럭션이든 그 숫자 만큼 반복하는 것과 같다
For example, for a count of 3:
.rept 3
movl $2, %eax
.endr
.rept와 .endr 안에 있는 내용을 3번 반복한다는 이야기...
This is equivalent to: (아래와 같은 의미이다....)
movl $2, %eax
movl $2, %eax
movl $2, %eax
In NASM, a similar construct is used at the preprocessor level. It begins with the %rep directive and ends with %endrep. The %rep directive is followed by an expression (unlike in GAS where the .rept directive is followed by a count):
NASM에서는 프리프로세서 레벨에서 간단한 구성개념이 사용되어진다. 이 것은 %rep 디렉티브로 시작하고 %endrep로 끝난다. %rep 디렉티브는 수식에 의해서 진행이 되어진다(rept 디렉티브가 count(인자의 갯수?)에 의해서 진행이 되는 GAS와 다르게...)
%rep <expression>
nop
%endrep
There is also an alternative in NASM, the times directive. Similar to %rep, it works at the assembler level, and it, too, is followed by an expression. For example, the above %rep construct is equivalent to this:
물론 NASM에서 times 디렉티브라는 대안이 존재한다.
문법은 아래와 같고...
times <expression> nop
즉, rep에서 아래 처럼 사용하면
And this:
%rep 3
mov eax, 2
%endrep
times는 아래 처럼 사용한다
is equivalent to this:
times 3 mov eax, 2
둘다 아래와 같은 의미이다...
and both are equivalent to this:
mov eax, 2
mov eax, 2
mov eax, 2
In Listing 5, the .rept (or %rep) directive is used to create a memory data area for 10 double words. The command line arguments are then accessed one by one from the stack and stored in the memory area until the command table gets full.
Listing5에서 .rept(또는 %rep) 디렉티브는 10 dobule word 크기의 메모리 데이타 영역을 만들기 위해서 사용되어 진다. 커맨드 라인 아규먼트는 스택에서 하나 하나 바로 접근이 되어지고 커맨드 테이블이 꽉 찰 때까지... 메모리 영역에 저장되어 진다.
As for command line arguments, they are accessed similarly with both assemblers. @ ESP or the top of the stack stores the number of command line arguments supplied to a program, which is 1 by default (for no command line arguments). esp + 4 stores the first command line argument, which is always the name of the program that was invoked from the command line. esp + 8, esp + 12, and so on store subsequent command line arguments.
커맨드 라인 아규먼트를 위해서(?), 그 것들은 어셈블러 모두에서 유사하게 접근되어진다. ESP 또는 스택의 탑은 프로그램에 주어지는 커맨드 라인 아규먼트의 수를 저장한다(?) 이 것은 기본적으로 1이다(커맨드 라인 아규먼트가 없을 때..) esp + 4은 첫번째 커맨트 라인 아규먼트를 저장한다. 이 것은 항상 프로그램의 이름인데 이 것은 커맨드 라인에서 다루어지는 이름이다. esp + 8, esp + 12, 그리고 기타 등등은 다음의 커맨드 라인 아규먼트를 저장한다.
Also watch the way the memory command table is being accessed on both sides in Listing 5. Here, memory indirect addressing mode (line 33) is used to access the command table along with an offset in ESI (and EDI) and a multiplier. Thus, [cmd_tbl + esi * 4] in NASM is equal to cmd_tbl(, %esi, 4) in GAS
물론, 메모리 커맨드 테이블은 Listing5에 있는 모두 접근되어지는 방법을 보거라~ 여기 33번째 줄에서 메모리 간접 어드레싱 모드는 ESI(그리고 EDI)에서 오프셋과 multiplier는 함께 커맨드 테이블을 접근하는데 사용되어 진다. 이와 같이 NASM에서 [cmd_tbl + esi * 4]은 GAS에서 cmd_tbl(, %esi, 4)와 같다.(흠...;;)
Conclusion
Even though the differences between these two assemblers are substantial, it's not that difficult to convert from one form to another. You might find that the AT&T syntax seems at first difficult to understand, but once mastered, it's as simple as the Intel syntax.
Resources
Learn
-
Consult the NASM and GAS manuals for complete introductions to these two assemblers:
- Read an explanation of selection sort on Wikipedia.
- In the developerWorks Linux zone, find more resources for Linux developers, and scan our most popular articles and tutorials.
- See all Linux tips and Linux tutorials on developerWorks.
- Stay current with developerWorks technical events and Webcasts.
Get products and technologies
- Order the SEK for Linux, a two-DVD set containing the latest IBM trial software for Linux from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
- With IBM trial software, available for download directly from developerWorks, build your next development project on Linux.
Discuss
- Get involved in the developerWorks community through blogs, forums, podcasts, and community topics in our new developerWorks spaces.
About the author
| Ram holds a post graduate degree in computer science and is working as a software engineer in IBM's India Software Labs, Rational Division, developing and adding features to Rational ClearCase. He has worked on various flavors of Linux, UNIX, and Windows, as well as real-time mobile-based operating systems such as Symbian and Windows Mobile. In his spare time he hacks Linux and reads books. |
History
Last edited on 03/27/2008 14:32 by noish
Comments (0)